android: Update catch2 to v2.7.0 am: e9410dfbd9 am: 651bdffab6
am: 1977c1ea93

Change-Id: I871e901aec134051da5636069eec4f42104b9ac0
diff --git a/.conan/build.py b/.conan/build.py
new file mode 100644
index 0000000..dfba264
--- /dev/null
+++ b/.conan/build.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+import os
+import re
+from cpt.packager import ConanMultiPackager
+from cpt.ci_manager import CIManager
+from cpt.printer import Printer
+
+
+class BuilderSettings(object):
+    @property
+    def username(self):
+        """ Set catchorg as package's owner
+        """
+        return os.getenv("CONAN_USERNAME", "catchorg")
+
+    @property
+    def login_username(self):
+        """ Set Bintray login username
+        """
+        return os.getenv("CONAN_LOGIN_USERNAME", "horenmar")
+
+    @property
+    def upload(self):
+        """ Set Catch2 repository to be used on upload.
+            The upload server address could be customized by env var
+            CONAN_UPLOAD. If not defined, the method will check the branch name.
+            Only master or CONAN_STABLE_BRANCH_PATTERN will be accepted.
+            The master branch will be pushed to testing channel, because it does
+            not match the stable pattern. Otherwise it will upload to stable
+            channel.
+        """
+        return os.getenv("CONAN_UPLOAD", "https://api.bintray.com/conan/catchorg/Catch2")
+
+    @property
+    def upload_only_when_stable(self):
+        """ Force to upload when running over tag branch
+        """
+        return os.getenv("CONAN_UPLOAD_ONLY_WHEN_STABLE", "True").lower() in ["true", "1", "yes"]
+
+    @property
+    def stable_branch_pattern(self):
+        """ Only upload the package the branch name is like a tag
+        """
+        return os.getenv("CONAN_STABLE_BRANCH_PATTERN", r"v\d+\.\d+\.\d+")
+
+    @property
+    def reference(self):
+        """ Read project version from branch create Conan referece
+        """
+        return os.getenv("CONAN_REFERENCE", "Catch2/{}".format(self._version))
+
+    @property
+    def channel(self):
+        """ Default Conan package channel when not stable
+        """
+        return os.getenv("CONAN_CHANNEL", "testing")
+
+    @property
+    def _version(self):
+        """ Get version name from cmake file
+        """
+        pattern = re.compile(r"project\(Catch2 LANGUAGES CXX VERSION (\d+\.\d+\.\d+)\)")
+        version = "latest"
+        with open("CMakeLists.txt") as file:
+            for line in file:
+                result = pattern.search(line)
+                if result:
+                    version = result.group(1)
+        return version
+
+    @property
+    def _branch(self):
+        """ Get branch name from CI manager
+        """
+        printer = Printer(None)
+        ci_manager = CIManager(printer)
+        return ci_manager.get_branch()
+
+
+if __name__ == "__main__":
+    settings = BuilderSettings()
+    builder = ConanMultiPackager(
+        reference=settings.reference,
+        channel=settings.channel,
+        upload=settings.upload,
+        upload_only_when_stable=settings.upload_only_when_stable,
+        stable_branch_pattern=settings.stable_branch_pattern,
+        login_username=settings.login_username,
+        username=settings.username,
+        test_folder=os.path.join(".conan", "test_package"))
+    builder.add()
+    builder.run()
diff --git a/.conan/test_package/CMakeLists.txt b/.conan/test_package/CMakeLists.txt
new file mode 100644
index 0000000..db05659
--- /dev/null
+++ b/.conan/test_package/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 3.2.0)
+project(test_package CXX)
+
+include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
+conan_basic_setup(TARGETS)
+
+find_package(Catch2 REQUIRED CONFIG)
+
+add_executable(${PROJECT_NAME} test_package.cpp)
+target_link_libraries(${PROJECT_NAME} CONAN_PKG::Catch2)
+set_target_properties(${PROJECT_NAME} PROPERTIES CXX_STANDARD 11)
diff --git a/.conan/test_package/conanfile.py b/.conan/test_package/conanfile.py
new file mode 100644
index 0000000..0a0da54
--- /dev/null
+++ b/.conan/test_package/conanfile.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+from conans import ConanFile, CMake
+import os
+
+
+class TestPackageConan(ConanFile):
+    settings = "os", "compiler", "build_type", "arch"
+    generators = "cmake"
+
+    def build(self):
+        cmake = CMake(self)
+        cmake.configure()
+        cmake.build()
+
+    def test(self):
+        assert os.path.isfile(os.path.join(self.deps_cpp_info["Catch2"].rootpath, "licenses", "LICENSE.txt"))
+        bin_path = os.path.join("bin", "test_package")
+        self.run("%s -s" % bin_path, run_environment=True)
diff --git a/.conan/test_package/test_package.cpp b/.conan/test_package/test_package.cpp
new file mode 100644
index 0000000..cff50de
--- /dev/null
+++ b/.conan/test_package/test_package.cpp
@@ -0,0 +1,15 @@
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+
+int Factorial( int number ) {
+    return number <= 1 ? 1 : Factorial( number - 1 ) * number;
+}
+
+TEST_CASE( "Factorial Tests", "[single-file]" ) {
+    REQUIRE( Factorial(0) == 1 );
+    REQUIRE( Factorial(1) == 1 );
+    REQUIRE( Factorial(2) == 2 );
+    REQUIRE( Factorial(3) == 6 );
+    REQUIRE( Factorial(10) == 3628800 );
+}
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
index 9e88eb4..23f98ff 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -10,8 +10,13 @@
 # Windows specific files should retain windows line-endings
 *.sln text eol=crlf
 
+# Keep executable scripts with LFs so they can be run after being
+# checked out on Windows
+*.py text eol=lf
+
+
 # Keep the single include header with LFs to make sure it is uploaded,
 # hashed etc with LF
-single_include/*.hpp eol=lf
+single_include/**/*.hpp eol=lf
 # Also keep the LICENCE file with LFs for the same reason
 LICENCE.txt eol=lf
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
new file mode 100644
index 0000000..dbeff11
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -0,0 +1,29 @@
+---
+name: Bug report
+about: Create an issue that documents a bug
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Describe the bug**
+A clear and concise description of what the bug is.
+
+**Expected behavior**
+A clear and concise description of what you expected to happen.
+
+**Reproduction steps**
+Steps to reproduce the bug.
+<!-- Usually this means a small and self-contained piece of code that uses Catch and specifying compiler flags if relevant. -->
+
+
+**Platform information:**
+<!-- Fill in any extra information that might be important for your issue. -->
+ - OS: **Windows NT**
+ - Compiler+version: **GCC v2.9.5**
+ - Catch version: **v1.2.3**
+
+
+**Additional context**
+Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
new file mode 100644
index 0000000..be9b9ee
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -0,0 +1,14 @@
+---
+name: Feature request
+about: Create an issue that requests a feature or other improvement
+title: ''
+labels: ''
+assignees: ''
+
+---
+
+**Description**
+Describe the feature/change you request and why do you want it.
+
+**Additional context**
+Add any other context or screenshots about the feature request here.
diff --git a/.github/issue_template.md b/.github/issue_template.md
deleted file mode 100644
index 051b5e5..0000000
--- a/.github/issue_template.md
+++ /dev/null
@@ -1,29 +0,0 @@
-## Description
-<!--
-If your issue is a bugreport, this means describing what you did,
-what did you want to happen and what actually did happen.
-
-If your issue is a feature request, describe the feature and why do you
-want it.
--->
-
-
-### Steps to reproduce
-<!--
-This is only relevant for bug reports, but if you do have one,
-please provide a minimal set of steps to reproduce the problem.
-
-Usually this means providing a small and self-contained code using Catch
-and specifying compiler flags/tools used if relevant.
--->
-
-
-### Extra information
-<!--
-Fill in any extra information that might be important for your issue.
-
-If your issue is a bugreport, definitely fill out at least the following.
--->
-* Catch version: **v42.42.42**
-* Operating System: **Joe's discount operating system**
-* Compiler+version: **Hidden Dragon v1.2.3**
diff --git a/.gitignore b/.gitignore
index ffce8e9..f017e9e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@
 .vs
 cmake-build-*
 benchmark-dir
+.conan/test_package/build
diff --git a/.travis.yml b/.travis.yml
index 1da1c0f..345edfb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,5 +1,8 @@
 language: cpp
-sudo: false
+
+branches:
+  except:
+  - /dev-appveyor.*/
 
 common_sources: &all_sources
   - ubuntu-toolchain-r-test
@@ -7,6 +10,7 @@
   - llvm-toolchain-trusty-3.9
   - llvm-toolchain-trusty-4.0
   - llvm-toolchain-trusty-5.0
+  - llvm-toolchain-trusty-6.0
 
 matrix:
   include:
@@ -17,145 +21,169 @@
       addons:
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'clang-3.5']
-      env: COMPILER='clang++-3.5' VALGRIND=1
+          packages: ['clang-3.5']
+      env: COMPILER='clang++-3.5'
 
     - os: linux
       compiler: clang
       addons:
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'clang-3.6']
-      env: COMPILER='clang++-3.6' VALGRIND=1
+          packages: ['clang-3.6']
+      env: COMPILER='clang++-3.6'
 
-# Travis's containers do not seem to have Clang 3.7 in apt, no matter what sources I add.
-#    - os: linux
-#      compiler: clang
-#      addons:
-#        apt:
-#          sources: *all_sources
-#          packages: ['valgrind', 'clang-3.7']
-#      env: COMPILER='clang++-3.7' VALGRIND=1
+    # Clang 3.7 is intentionally skipped as we cannot get it easily on
+    # TravisCI container
 
     - os: linux
       compiler: clang
       addons:
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'clang-3.8']
-      env: COMPILER='clang++-3.8' VALGRIND=1
+          packages: ['lcov', 'clang-3.8']
+      env: COMPILER='clang++-3.8'
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-3.9', 'valgrind', 'lcov']
-      env: COMPILER='clang++-3.9' VALGRIND=1
+              packages: ['clang-3.9']
+      env: COMPILER='clang++-3.9'
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-4.0', 'valgrind', 'lcov']
-      env: COMPILER='clang++-4.0' VALGRIND=1
+              packages: ['clang-4.0']
+      env: COMPILER='clang++-4.0'
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-5.0', 'valgrind', 'lcov']
-      env: COMPILER='clang++-5.0' VALGRIND=1
+              packages: ['clang-5.0']
+      env: COMPILER='clang++-5.0'
+
+    - os: linux
+      compiler: clang
+      addons:
+          apt:
+              sources: *all_sources
+              packages: ['clang-6.0']
+      env: COMPILER='clang++-6.0'
 
     # 2/ Linux GCC Builds
     - os: linux
       compiler: gcc
       addons:
         apt:
-         sources: ['ubuntu-toolchain-r-test']
-         packages: ['valgrind', 'lcov', 'g++-4.8']
-      env: COMPILER='g++-4.8' VALGRIND=1
+         sources: *all_sources
+         packages: ['g++-4.8']
+      env: COMPILER='g++-4.8'
 
     - os: linux
       compiler: gcc
       addons:
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'g++-4.9']
-      env: COMPILER='g++-4.9' VALGRIND=1
+          packages: ['g++-4.9']
+      env: COMPILER='g++-4.9'
 
     - os: linux
       compiler: gcc
       addons:
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'g++-5']
-      env: COMPILER='g++-5' VALGRIND=1
+          packages: ['g++-5']
+      env: COMPILER='g++-5'
 
     - os: linux
       compiler: gcc
       addons: &gcc6
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'g++-6']
-      env: COMPILER='g++-6' VALGRIND=1
+          packages: ['g++-6']
+      env: COMPILER='g++-6'
 
     - os: linux
       compiler: gcc
       addons: &gcc7
         apt:
           sources: *all_sources
-          packages: ['valgrind', 'lcov', 'g++-7']
-      env: COMPILER='g++-7' VALGRIND=1
+          packages: ['g++-7']
+      env: COMPILER='g++-7'
+
+    - os: linux
+      compiler: gcc
+      addons: &gcc8
+        apt:
+          sources: *all_sources
+          packages: ['g++-8']
+      env: COMPILER='g++-8'
 
     # 3b/ Linux C++14 Clang builds
+    # Note that we need newer libstdc++ for C++14 support
     - os: linux
       compiler: clang
       addons:
           apt:
-              packages: ['clang-3.8', 'valgrind', 'lcov', 'libstdc++-6-dev']
+              packages: ['clang-3.8', 'libstdc++-6-dev']
               sources:
                   - ubuntu-toolchain-r-test
                   - llvm-toolchain-trusty
-      env: COMPILER='clang++-3.8' CPP14=1 VALGRIND=1
+      env: COMPILER='clang++-3.8' CPP14=1
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-3.9', 'valgrind', 'lcov', 'libstdc++-6-dev']
-      env: COMPILER='clang++-3.9' CPP14=1 VALGRIND=1
+              packages: ['clang-3.9', 'libstdc++-6-dev']
+      env: COMPILER='clang++-3.9' CPP14=1
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-4.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
-      env: COMPILER='clang++-4.0' CPP14=1 VALGRIND=1
+              packages: ['clang-4.0', 'libstdc++-6-dev']
+      env: COMPILER='clang++-4.0' CPP14=1
 
     - os: linux
       compiler: clang
       addons:
           apt:
               sources: *all_sources
-              packages: ['clang-5.0', 'valgrind', 'lcov', 'libstdc++-6-dev']
-      env: COMPILER='clang++-5.0' CPP14=1 VALGRIND=1
+              packages: ['clang-5.0', 'libstdc++-6-dev']
+      env: COMPILER='clang++-5.0' CPP14=1
+
+    - os: linux
+      compiler: clang
+      addons:
+          apt:
+              sources: *all_sources
+              packages: ['clang-6.0', 'libstdc++-6-dev']
+      env: COMPILER='clang++-6.0' CPP14=1
 
 
     # 4a/ Linux C++14 GCC builds
     - os: linux
       compiler: gcc
       addons: *gcc6
-      env: COMPILER='g++-6' CPP14=1 VALGRIND=1
+      env: COMPILER='g++-6' CPP14=1
 
     - os: linux
       compiler: gcc
       addons: *gcc7
-      env: COMPILER='g++-7' CPP14=1 VALGRIND=1
+      env: COMPILER='g++-7' CPP14=1
+
+    - os: linux
+      compiler: gcc
+      addons: *gcc8
+      env: COMPILER='g++-8' CPP14=1
 
     # 5/ OSX Clang Builds
     - os: osx
@@ -181,15 +209,86 @@
     - os: osx
       osx_image: xcode9.1
       compiler: clang
-      env: COMPILER='clang++' USE_CPP14=1
+      env: COMPILER='clang++' CPP14=1
 
+    # 6/ Special builds -- examples, coverage, valgrind, etc.
+    - os: linux
+      compiler: gcc
+      addons:
+        apt:
+          sources: *all_sources
+          packages: ['lcov', 'g++-7']
+      env: COMPILER='g++-7' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
+
+    - os: linux
+      compiler: clang
+      addons:
+        apt:
+          packages: ['clang-3.8', 'lcov']
+          sources:
+            - ubuntu-toolchain-r-test
+            - llvm-toolchain-trusty
+      env: COMPILER='clang++-3.8' EXAMPLES=1 COVERAGE=1 EXTRAS=1
+
+    - os: linux
+      compiler: gcc
+      addons:
+        apt:
+          sources: *all_sources
+          packages: ['valgrind', 'lcov', 'g++-7']
+      env: COMPILER='g++-7' CPP14=1 VALGRIND=1
+
+    - os: osx
+      osx_image: xcode9.1
+      compiler: clang
+      env: COMPILER='clang++' CPP14=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
+
+    # 7/ C++17 builds
+    - os: linux
+      compiler: gcc
+      addons: *gcc7
+      env: COMPILER='g++-7' CPP17=1
+
+    - os: linux
+      compiler: gcc
+      addons: *gcc7
+      env: COMPILER='g++-7' EXAMPLES=1 COVERAGE=1 EXTRAS=1 CPP17=1
+
+    - os: linux
+      compiler: clang
+      addons:
+          apt:
+              sources: *all_sources
+              packages: ['clang-6.0', 'libstdc++-8-dev']
+      env: COMPILER='clang++-6.0' CPP17=1
+
+    - os: linux
+      compiler: clang
+      addons:
+          apt:
+              sources: *all_sources
+              packages: ['clang-6.0', 'libstdc++-8-dev']
+      env: COMPILER='clang++-6.0' CPP17=1 EXAMPLES=1 COVERAGE=1 EXTRAS=1
+
+    # 8/ Conan
+    - language: python
+      python:
+        - "3.7"
+      dist: xenial
+      install:
+        - pip install conan==1.10.2 conan-package-tools
+      env:
+        - CONAN_GCC_VERSIONS=8
+        - CONAN_DOCKER_IMAGE=conanio/gcc8
+      script:
+        - python .conan/build.py
 
 install:
   - DEPS_DIR="${TRAVIS_BUILD_DIR}/deps"
   - mkdir -p ${DEPS_DIR} && cd ${DEPS_DIR}
   - |
     if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
-      CMAKE_URL="http://www.cmake.org/files/v3.3/cmake-3.3.2-Linux-x86_64.tar.gz"
+      CMAKE_URL="http://cmake.org/files/v3.8/cmake-3.8.2-Linux-x86_64.tar.gz"
       mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake
       export PATH=${DEPS_DIR}/cmake/bin:${PATH}
     elif [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then
@@ -202,25 +301,24 @@
   # Regenerate single header file, so it is tested in the examples...
   - python scripts/generateSingleHeader.py
 
-  - |
     # Use Debug builds for running Valgrind and building examples
-    cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=ON -DCATCH_ENABLE_COVERAGE=ON
+  - cmake -H. -BBuild-Debug -DCMAKE_BUILD_TYPE=Debug -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17} -DCATCH_USE_VALGRIND=${VALGRIND} -DCATCH_BUILD_EXAMPLES=${EXAMPLES} -DCATCH_ENABLE_COVERAGE=${COVERAGE} -DCATCH_BUILD_EXTRA_TESTS=${EXTRAS}
     # Don't bother with release build for coverage build
-    cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14}
+  - cmake -H. -BBuild-Release -DCMAKE_BUILD_TYPE=Release -Wdev -DUSE_CPP14=${CPP14} -DUSE_CPP17=${CPP17}
 
 
 script:
-  - |
-    cd Build-Debug
-    make -j 2
-    CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
+  - cd Build-Debug
+  - make -j 2
+  - CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
     # Coverage collection does not work for OS X atm
-    if [[ "${TRAVIS_OS_NAME}" == "linux" ]]; then
+  - |
+    if [[ "${TRAVIS_OS_NAME}" == "linux" ]] && [[ "${COVERAGE}" == "1" ]]; then
       make gcov
       make lcov
       bash <(curl -s https://codecov.io/bash) -X gcov || echo "Codecov did not collect coverage reports"
     fi
-    # Go to release build
-    cd ../Build-Release
-    make -j 2
-    CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
+  - # Go to release build
+  - cd ../Build-Release
+  - make -j 2
+  - CTEST_OUTPUT_ON_FAILURE=1 ctest -j 2
diff --git a/Android.bp b/Android.bp
index 42df9d6..4852cf0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -18,6 +18,7 @@
     local_include_dirs: ["include"],  // cc_test ignores export_include_dirs
     export_include_dirs: ["include"],
     srcs: ["include/**/*.cpp"],
+    exclude_srcs: ["include/catch_with_main.cpp"],
 }
 
 // !!! IMPORTANT: Use 'whole_static_libs' or the linker will dead-code-eliminate
@@ -33,9 +34,7 @@
         "libcatch2-defaults",
     ],
     srcs: [
-        // cannot use catch_with_main.hpp as main, soong errors with "has unknown extension"
-        // "include/catch_with_main.hpp",
-        "examples/000-CatchMain.cpp",
+        "include/catch_with_main.cpp",
     ],
 }
 
@@ -46,6 +45,7 @@
     defaults: [
         "libcatch2-defaults",
     ],
+    cflags: ["-DCATCH_CONFIG_DISABLE_EXCEPTIONS"],
 }
 
 // This rule can be used by other external/ projects that depend on catch2
@@ -55,7 +55,6 @@
     defaults: [
         "libcatch2-defaults",
     ],
-    rtti: true,
     cflags: ["-fexceptions"],
 }
 
@@ -74,7 +73,7 @@
     ],
 }
 
-// Upstream config: RTTI and exceptions are enabled.
+// Upstream config: Exceptions are enabled.
 // This should be validated first after an upstream merge.
 cc_test {
     name: "libcatch2-tests-upstream",
@@ -83,7 +82,6 @@
     ],
 
     gtest: false,
-    rtti: true,
     cflags: ["-fexceptions"],
 
     whole_static_libs: [
@@ -91,13 +89,17 @@
     ],
 }
 
-// Android config: RTTI and exceptions are disabled.
+// Android config: Exceptions are disabled.
 // This should be validated second after an upstream merge.
 cc_test {
     name: "libcatch2-tests",
     defaults: [
         "libcatch2-defaults-tests",
     ],
+    cflags: [
+        "-DCATCH_CONFIG_DISABLE_EXCEPTIONS",
+        "-Wno-unused-function",
+    ],
     gtest: false,
     whole_static_libs: [
         "libcatch2",
diff --git a/CMake/Catch2Config.cmake.in b/CMake/Catch2Config.cmake.in
new file mode 100644
index 0000000..c485219
--- /dev/null
+++ b/CMake/Catch2Config.cmake.in
@@ -0,0 +1,10 @@
+@PACKAGE_INIT@
+
+
+# Avoid repeatedly including the targets
+if(NOT TARGET Catch2::Catch2)
+    # Provide path for scripts
+    list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
+
+    include(${CMAKE_CURRENT_LIST_DIR}/Catch2Targets.cmake)
+endif()
diff --git a/CMake/MiscFunctions.cmake b/CMake/MiscFunctions.cmake
new file mode 100644
index 0000000..262f7cd
--- /dev/null
+++ b/CMake/MiscFunctions.cmake
@@ -0,0 +1,26 @@
+#checks that the given hard-coded list contains all headers + sources in the given folder
+function(CheckFileList LIST_VAR FOLDER)
+  set(MESSAGE " should be added to the variable ${LIST_VAR}")
+  set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
+  file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
+                         "${FOLDER}/*.hpp"
+                         "${FOLDER}/*.h")
+  list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
+  foreach(EXTRA_ITEM ${GLOBBED_LIST})
+    string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
+    message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
+  endforeach()
+endfunction()
+
+function(CheckFileListRec LIST_VAR FOLDER)
+  set(MESSAGE " should be added to the variable ${LIST_VAR}")
+  set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
+  file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
+                                 "${FOLDER}/*.hpp"
+                                 "${FOLDER}/*.h")
+  list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
+  foreach(EXTRA_ITEM ${GLOBBED_LIST})
+    string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
+    message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
+  endforeach()
+endfunction()
diff --git a/CMake/catch2.pc.in b/CMake/catch2.pc.in
new file mode 100644
index 0000000..3ac9fbd
--- /dev/null
+++ b/CMake/catch2.pc.in
@@ -0,0 +1,7 @@
+includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
+
+Name: Catch2
+Description: A modern, C++-native, header-only, test framework for C++11
+URL: https://github.com/catchorg/Catch2
+Version: @Catch2_VERSION@
+Cflags: -I${includedir}
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 19472de..ea35d24 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,4 +1,4 @@
-cmake_minimum_required(VERSION 3.0)
+cmake_minimum_required(VERSION 3.5)
 
 # detect if Catch is being bundled,
 # disable testsuite in that case
@@ -6,14 +6,24 @@
   set(NOT_SUBPROJECT ON)
 endif()
 
-project(Catch2 LANGUAGES CXX VERSION 2.1.1)
+project(Catch2 LANGUAGES CXX VERSION 2.7.0)
+
+# Provide path for scripts
+list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
 
 include(GNUInstallDirs)
+include(CMakePackageConfigHelpers)
+include(CTest)
 
 option(CATCH_USE_VALGRIND "Perform SelfTests with Valgrind" OFF)
+option(CATCH_BUILD_TESTING "Build SelfTest project" ON)
 option(CATCH_BUILD_EXAMPLES "Build documentation examples" OFF)
+option(CATCH_BUILD_EXTRA_TESTS "Build extra tests" OFF)
 option(CATCH_ENABLE_COVERAGE "Generate coverage for codecov.io" OFF)
 option(CATCH_ENABLE_WERROR "Enable all warnings as errors" ON)
+option(CATCH_INSTALL_DOCS "Install documentation alongside library" ON)
+option(CATCH_INSTALL_HELPERS "Install contrib alongside library" ON)
+
 
 set_property(GLOBAL PROPERTY USE_FOLDERS ON)
 
@@ -27,381 +37,172 @@
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /ENTRY:wmainCRTStartup")
 endif()
 
-#checks that the given hard-coded list contains all headers + sources in the given folder
-function(CheckFileList LIST_VAR FOLDER)
-  set(MESSAGE " should be added to the variable ${LIST_VAR}")
-  set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
-  file(GLOB GLOBBED_LIST "${FOLDER}/*.cpp"
-                         "${FOLDER}/*.hpp"
-                         "${FOLDER}/*.h")
-  list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
-  foreach(EXTRA_ITEM ${GLOBBED_LIST})
-    string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
-    message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
-  endforeach()
-endfunction()
-
-function(CheckFileListRec LIST_VAR FOLDER)
-  set(MESSAGE " should be added to the variable ${LIST_VAR}")
-  set(MESSAGE "${MESSAGE} in ${CMAKE_CURRENT_LIST_FILE}\n")
-  file(GLOB_RECURSE GLOBBED_LIST "${FOLDER}/*.cpp"
-                                 "${FOLDER}/*.hpp"
-                                 "${FOLDER}/*.h")
-  list(REMOVE_ITEM GLOBBED_LIST ${${LIST_VAR}})
-  foreach(EXTRA_ITEM ${GLOBBED_LIST})
-    string(REPLACE "${CATCH_DIR}/" "" RELATIVE_FILE_NAME "${EXTRA_ITEM}")
-    message(AUTHOR_WARNING "The file \"${RELATIVE_FILE_NAME}\"${MESSAGE}")
-  endforeach()
-endfunction()
-
-# define the sources of the self test
-# Please keep these ordered alphabetically
-set(TEST_SOURCES
-        ${SELF_TEST_DIR}/TestMain.cpp
-        ${SELF_TEST_DIR}/IntrospectiveTests/CmdLine.tests.cpp
-        ${SELF_TEST_DIR}/IntrospectiveTests/PartTracker.tests.cpp
-        ${SELF_TEST_DIR}/IntrospectiveTests/TagAlias.tests.cpp
-        ${SELF_TEST_DIR}/IntrospectiveTests/String.tests.cpp
-        ${SELF_TEST_DIR}/IntrospectiveTests/Xml.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Approx.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/BDD.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Benchmark.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Class.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Compilation.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Condition.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Decomposition.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/EnumToString.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Exception.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Message.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Misc.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringChrono.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringGeneral.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringPair.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringTuple.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringVector.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/ToStringWhich.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Tricky.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/VariadicMacros.tests.cpp
-        ${SELF_TEST_DIR}/UsageTests/Matchers.tests.cpp
-        )
-CheckFileList(TEST_SOURCES ${SELF_TEST_DIR})
-
-# A set of impl files that just #include a single header
-# Please keep these ordered alphabetically
-set(SURROGATE_SOURCES
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_console_colour.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_debugger.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_interfaces_reporter.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_option.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_stream.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_test_case_tracker.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_test_spec.cpp
-        ${SELF_TEST_DIR}/SurrogateCpps/catch_xmlwriter.cpp
-        )
-CheckFileList(SURROGATE_SOURCES ${SELF_TEST_DIR}/SurrogateCpps)
-
-
-# Please keep these ordered alphabetically
-set(TOP_LEVEL_HEADERS
-        ${HEADER_DIR}/catch.hpp
-        ${HEADER_DIR}/catch_with_main.hpp
-        )
-CheckFileList(TOP_LEVEL_HEADERS ${HEADER_DIR})
-
-# Please keep these ordered alphabetically
-set(EXTERNAL_HEADERS
-        ${HEADER_DIR}/external/clara.hpp
-        )
-CheckFileList(EXTERNAL_HEADERS ${HEADER_DIR}/external)
-
-
-# Please keep these ordered alphabetically
-set(INTERNAL_HEADERS
-        ${HEADER_DIR}/internal/catch_approx.h
-        ${HEADER_DIR}/internal/catch_assertionhandler.h
-        ${HEADER_DIR}/internal/catch_assertioninfo.h
-        ${HEADER_DIR}/internal/catch_assertionresult.h
-        ${HEADER_DIR}/internal/catch_capture.hpp
-        ${HEADER_DIR}/internal/catch_capture_matchers.h
-        ${HEADER_DIR}/internal/catch_clara.h
-        ${HEADER_DIR}/internal/catch_commandline.h
-        ${HEADER_DIR}/internal/catch_common.h
-        ${HEADER_DIR}/internal/catch_compiler_capabilities.h
-        ${HEADER_DIR}/internal/catch_config.hpp
-        ${HEADER_DIR}/internal/catch_console_colour.h
-        ${HEADER_DIR}/internal/catch_context.h
-        ${HEADER_DIR}/internal/catch_debug_console.h
-        ${HEADER_DIR}/internal/catch_debugger.h
-        ${HEADER_DIR}/internal/catch_decomposer.h
-        ${HEADER_DIR}/internal/catch_default_main.hpp
-        ${HEADER_DIR}/internal/catch_enforce.h
-        ${HEADER_DIR}/internal/catch_errno_guard.h
-        ${HEADER_DIR}/internal/catch_exception_translator_registry.h
-        ${HEADER_DIR}/internal/catch_external_interfaces.h
-        ${HEADER_DIR}/internal/catch_fatal_condition.h
-        ${HEADER_DIR}/internal/catch_impl.hpp
-        ${HEADER_DIR}/internal/catch_interfaces_capture.h
-        ${HEADER_DIR}/internal/catch_interfaces_config.h
-        ${HEADER_DIR}/internal/catch_interfaces_exception.h
-        ${HEADER_DIR}/internal/catch_interfaces_registry_hub.h
-        ${HEADER_DIR}/internal/catch_interfaces_reporter.h
-        ${HEADER_DIR}/internal/catch_interfaces_runner.h
-        ${HEADER_DIR}/internal/catch_interfaces_tag_alias_registry.h
-        ${HEADER_DIR}/internal/catch_interfaces_testcase.h
-        ${HEADER_DIR}/internal/catch_leak_detector.h
-        ${HEADER_DIR}/internal/catch_list.h
-        ${HEADER_DIR}/internal/catch_matchers.h
-        ${HEADER_DIR}/internal/catch_matchers_floating.h
-        ${HEADER_DIR}/internal/catch_matchers_string.h
-        ${HEADER_DIR}/internal/catch_matchers_vector.h
-        ${HEADER_DIR}/internal/catch_message.h
-        ${HEADER_DIR}/internal/catch_objc.hpp
-        ${HEADER_DIR}/internal/catch_objc_arc.hpp
-        ${HEADER_DIR}/internal/catch_option.hpp
-        ${HEADER_DIR}/internal/catch_platform.h
-        ${HEADER_DIR}/internal/catch_random_number_generator.h
-        ${HEADER_DIR}/internal/catch_reenable_warnings.h
-        ${HEADER_DIR}/internal/catch_reporter_registrars.hpp
-        ${HEADER_DIR}/internal/catch_reporter_registry.h
-        ${HEADER_DIR}/internal/catch_result_type.h
-        ${HEADER_DIR}/internal/catch_run_context.h
-        ${HEADER_DIR}/internal/catch_benchmark.h
-        ${HEADER_DIR}/internal/catch_section.h
-        ${HEADER_DIR}/internal/catch_section_info.h
-        ${HEADER_DIR}/internal/catch_session.h
-        ${HEADER_DIR}/internal/catch_startup_exception_registry.h
-        ${HEADER_DIR}/internal/catch_stream.h
-        ${HEADER_DIR}/internal/catch_stringref.h
-        ${HEADER_DIR}/internal/catch_string_manip.h
-        ${HEADER_DIR}/internal/catch_suppress_warnings.h
-        ${HEADER_DIR}/internal/catch_tag_alias.h
-        ${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.h
-        ${HEADER_DIR}/internal/catch_tag_alias_registry.h
-        ${HEADER_DIR}/internal/catch_test_case_info.h
-        ${HEADER_DIR}/internal/catch_test_case_registry_impl.h
-        ${HEADER_DIR}/internal/catch_test_case_tracker.h
-        ${HEADER_DIR}/internal/catch_test_registry.h
-        ${HEADER_DIR}/internal/catch_test_spec.h
-        ${HEADER_DIR}/internal/catch_test_spec_parser.h
-        ${HEADER_DIR}/internal/catch_text.h
-        ${HEADER_DIR}/internal/catch_timer.h
-        ${HEADER_DIR}/internal/catch_tostring.h
-        ${HEADER_DIR}/internal/catch_totals.h
-        ${HEADER_DIR}/internal/catch_uncaught_exceptions.h
-        ${HEADER_DIR}/internal/catch_user_interfaces.h
-        ${HEADER_DIR}/internal/catch_version.h
-        ${HEADER_DIR}/internal/catch_wildcard_pattern.h
-        ${HEADER_DIR}/internal/catch_windows_h_proxy.h
-        ${HEADER_DIR}/internal/catch_xmlwriter.h
-        )
-set(IMPL_SOURCES
-        ${HEADER_DIR}/internal/catch_approx.cpp
-        ${HEADER_DIR}/internal/catch_assertionhandler.cpp
-        ${HEADER_DIR}/internal/catch_assertionresult.cpp
-        ${HEADER_DIR}/internal/catch_benchmark.cpp
-        ${HEADER_DIR}/internal/catch_capture_matchers.cpp
-        ${HEADER_DIR}/internal/catch_commandline.cpp
-        ${HEADER_DIR}/internal/catch_common.cpp
-        ${HEADER_DIR}/internal/catch_config.cpp
-        ${HEADER_DIR}/internal/catch_console_colour.cpp
-        ${HEADER_DIR}/internal/catch_context.cpp
-        ${HEADER_DIR}/internal/catch_debug_console.cpp
-        ${HEADER_DIR}/internal/catch_debugger.cpp
-        ${HEADER_DIR}/internal/catch_decomposer.cpp
-        ${HEADER_DIR}/internal/catch_errno_guard.cpp
-        ${HEADER_DIR}/internal/catch_exception_translator_registry.cpp
-        ${HEADER_DIR}/internal/catch_fatal_condition.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_capture.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_config.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_exception.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_registry_hub.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_runner.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_testcase.cpp
-        ${HEADER_DIR}/internal/catch_list.cpp
-        ${HEADER_DIR}/internal/catch_leak_detector.cpp
-        ${HEADER_DIR}/internal/catch_matchers.cpp
-        ${HEADER_DIR}/internal/catch_matchers_floating.cpp
-        ${HEADER_DIR}/internal/catch_matchers_string.cpp
-        ${HEADER_DIR}/internal/catch_message.cpp
-        ${HEADER_DIR}/internal/catch_registry_hub.cpp
-        ${HEADER_DIR}/internal/catch_interfaces_reporter.cpp
-        ${HEADER_DIR}/internal/catch_random_number_generator.cpp
-        ${HEADER_DIR}/internal/catch_reporter_registry.cpp
-        ${HEADER_DIR}/internal/catch_result_type.cpp
-        ${HEADER_DIR}/internal/catch_run_context.cpp
-        ${HEADER_DIR}/internal/catch_section.cpp
-        ${HEADER_DIR}/internal/catch_section_info.cpp
-        ${HEADER_DIR}/internal/catch_session.cpp
-        ${HEADER_DIR}/internal/catch_startup_exception_registry.cpp
-        ${HEADER_DIR}/internal/catch_stream.cpp
-        ${HEADER_DIR}/internal/catch_stringref.cpp
-        ${HEADER_DIR}/internal/catch_string_manip.cpp
-        ${HEADER_DIR}/internal/catch_tag_alias.cpp
-        ${HEADER_DIR}/internal/catch_tag_alias_autoregistrar.cpp
-        ${HEADER_DIR}/internal/catch_tag_alias_registry.cpp
-        ${HEADER_DIR}/internal/catch_test_case_info.cpp
-        ${HEADER_DIR}/internal/catch_test_case_registry_impl.cpp
-        ${HEADER_DIR}/internal/catch_test_case_tracker.cpp
-        ${HEADER_DIR}/internal/catch_test_registry.cpp
-        ${HEADER_DIR}/internal/catch_test_spec.cpp
-        ${HEADER_DIR}/internal/catch_test_spec_parser.cpp
-        ${HEADER_DIR}/internal/catch_timer.cpp
-        ${HEADER_DIR}/internal/catch_tostring.cpp
-        ${HEADER_DIR}/internal/catch_totals.cpp
-        ${HEADER_DIR}/internal/catch_uncaught_exceptions.cpp
-        ${HEADER_DIR}/internal/catch_version.cpp
-        ${HEADER_DIR}/internal/catch_wildcard_pattern.cpp
-        ${HEADER_DIR}/internal/catch_xmlwriter.cpp
-        )
-set(INTERNAL_FILES ${IMPL_SOURCES} ${INTERNAL_HEADERS})
-CheckFileList(INTERNAL_FILES ${HEADER_DIR}/internal)
-
-# Please keep these ordered alphabetically
-set(REPORTER_HEADERS
-        ${HEADER_DIR}/reporters/catch_reporter_automake.hpp
-        ${HEADER_DIR}/reporters/catch_reporter_bases.hpp
-        ${HEADER_DIR}/reporters/catch_reporter_compact.h
-        ${HEADER_DIR}/reporters/catch_reporter_console.h
-        ${HEADER_DIR}/reporters/catch_reporter_junit.h
-        ${HEADER_DIR}/reporters/catch_reporter_multi.h
-        ${HEADER_DIR}/reporters/catch_reporter_tap.hpp
-        ${HEADER_DIR}/reporters/catch_reporter_teamcity.hpp
-        ${HEADER_DIR}/reporters/catch_reporter_xml.h
-        )
-set(REPORTER_SOURCES
-        ${HEADER_DIR}/reporters/catch_reporter_bases.cpp
-        ${HEADER_DIR}/reporters/catch_reporter_compact.cpp
-        ${HEADER_DIR}/reporters/catch_reporter_console.cpp
-        ${HEADER_DIR}/reporters/catch_reporter_junit.cpp
-        ${HEADER_DIR}/reporters/catch_reporter_multi.cpp
-        ${HEADER_DIR}/reporters/catch_reporter_xml.cpp
-        )
-set(REPORTER_FILES ${REPORTER_HEADERS} ${REPORTER_SOURCES})
-CheckFileList(REPORTER_FILES ${HEADER_DIR}/reporters)
-
-# Specify the headers, too, so CLion recognises them as project files
-set(HEADERS
-        ${TOP_LEVEL_HEADERS}
-        ${EXTERNAL_HEADERS}
-        ${INTERNAL_HEADERS}
-        ${REPORTER_HEADERS}
-        )
-
-# Provide some groupings for IDEs
-SOURCE_GROUP("Tests" FILES ${TEST_SOURCES})
-SOURCE_GROUP("Surrogates" FILES ${SURROGATE_SOURCES})
-
-
-# Projects consuming Catch via ExternalProject_Add might want to use install step
-# without building all of our selftests.
-
-if(DEFINED NO_SELFTEST)
-    message(DEPRECATION "*** CMake option NO_SELFTEST is deprecated; use BUILD_TESTING instead")
-    if (NO_SELFTEST)
-        set(BUILD_TESTING OFF CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
-    else()
-        set(BUILD_TESTING ON CACHE BOOL "Disable Catch2 internal testsuite" FORCE)
+if (BUILD_TESTING AND CATCH_BUILD_TESTING AND NOT_SUBPROJECT)
+    find_package(PythonInterp)
+    if (NOT PYTHONINTERP_FOUND)
+        message(FATAL_ERROR "Python not found, but required for tests")
     endif()
+    add_subdirectory(projects)
 endif()
 
-include(CTest)
-
-if (BUILD_TESTING AND NOT_SUBPROJECT)
-    add_executable(SelfTest ${TEST_SOURCES} ${IMPL_SOURCES} ${REPORTER_SOURCES} ${SURROGATE_SOURCES} ${HEADERS})
-    target_include_directories(SelfTest PRIVATE ${HEADER_DIR})
-
-    if(USE_CPP14)
-        message(STATUS "Enabling C++14")
-        set_property(TARGET SelfTest PROPERTY CXX_STANDARD 14)
-    else()
-        message(STATUS "Enabling C++11")
-        set_property(TARGET SelfTest PROPERTY CXX_STANDARD 11)
-    endif()
-
-    set_property(TARGET SelfTest PROPERTY CXX_STANDARD_REQUIRED ON)
-    set_property(TARGET SelfTest PROPERTY CXX_EXTENSIONS OFF)
-
-    if (CATCH_ENABLE_COVERAGE)
-        set(ENABLE_COVERAGE ON CACHE BOOL "Enable coverage build." FORCE)
-        list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/CMake")
-        find_package(codecov)
-        add_coverage(SelfTest)
-        list(APPEND LCOV_REMOVE_PATTERNS "'/usr/*'")
-        coverage_evaluate()
-    endif()
-
-    # Add desired warnings
-    if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
-        target_compile_options( SelfTest PRIVATE -Wall -Wextra -Wunreachable-code -Wpedantic)
-        if (CATCH_ENABLE_WERROR)
-            target_compile_options( SelfTest PRIVATE -Werror)
-        endif()
-    endif()
-    # Clang specific warning go here
-    if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" )
-        # Actually keep these
-        target_compile_options( SelfTest PRIVATE -Wweak-vtables -Wexit-time-destructors -Wglobal-constructors -Wmissing-noreturn )
-    endif()
-    if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
-		STRING(REGEX REPLACE "/W[0-9]" "/W4" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS}) # override default warning level
-        target_compile_options( SelfTest PRIVATE /w44265 /w44061 /w44062 )
-        if (CATCH_ENABLE_WERROR)
-            target_compile_options( SelfTest PRIVATE /WX)
-        endif()
-    endif()
-
-
-    # configure unit tests via CTest
-    include(CTest)
-    add_test(NAME RunTests COMMAND $<TARGET_FILE:SelfTest>)
-
-    add_test(NAME ListTests COMMAND $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
-    set_tests_properties(ListTests PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ test cases")
-
-    add_test(NAME ListTags COMMAND $<TARGET_FILE:SelfTest> --list-tags)
-    set_tests_properties(ListTags PROPERTIES PASS_REGULAR_EXPRESSION "[0-9]+ tags")
-
-    add_test(NAME ListReporters COMMAND $<TARGET_FILE:SelfTest> --list-reporters)
-    set_tests_properties(ListReporters PROPERTIES PASS_REGULAR_EXPRESSION "Available reporters:")
-
-    add_test(NAME ListTestNamesOnly COMMAND $<TARGET_FILE:SelfTest> --list-test-names-only)
-    set_tests_properties(ListTestNamesOnly PROPERTIES PASS_REGULAR_EXPRESSION "Regex string matcher")
-
-
-
-    # AppVeyor has a Python 2.7 in path, but doesn't have .py files as autorunnable
-    add_test(NAME ApprovalTests COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/scripts/approvalTests.py $<TARGET_FILE:SelfTest>)
-    set_tests_properties(ApprovalTests PROPERTIES FAIL_REGULAR_EXPRESSION "Results differed")
-
-    if (CATCH_USE_VALGRIND)
-        add_test(NAME ValgrindRunTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest>)
-        add_test(NAME ValgrindListTests COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tests --verbosity high)
-        set_tests_properties(ValgrindListTests PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
-        add_test(NAME ValgrindListTags COMMAND valgrind --leak-check=full --error-exitcode=1 $<TARGET_FILE:SelfTest> --list-tags)
-        set_tests_properties(ValgrindListTags PROPERTIES PASS_REGULAR_EXPRESSION "definitely lost: 0 bytes in 0 blocks")
-    endif()
-
-endif() # !NO_SELFTEST
-
-
 if(CATCH_BUILD_EXAMPLES)
     add_subdirectory(examples)
 endif()
 
-install(DIRECTORY "single_include/" DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/catch")
+if(CATCH_BUILD_EXTRA_TESTS)
+    add_subdirectory(projects/ExtraTests)
+endif()
 
-install(DIRECTORY docs/ DESTINATION "${CMAKE_INSTALL_DOCDIR}")
+# add catch as a 'linkable' target
+add_library(Catch2 INTERFACE)
 
-## Provide some pkg-config integration
-# Don't bother on Windows
-if(NOT WIN32 OR NOT CMAKE_HOST_SYSTEM_NAME MATCHES Windows)
 
-    set(PKGCONFIG_INSTALL_DIR
-        "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
-        CACHE PATH "Path where catch.pc is installed"
+
+# depend on some obvious c++11 features so the dependency is transitively added dependents
+target_compile_features(Catch2
+  INTERFACE
+    cxx_alignas
+    cxx_alignof
+    cxx_attributes
+    cxx_auto_type
+    cxx_constexpr
+    cxx_defaulted_functions
+    cxx_deleted_functions
+    cxx_final
+    cxx_lambdas
+    cxx_noexcept
+    cxx_override
+    cxx_range_for
+    cxx_rvalue_references
+    cxx_static_assert
+    cxx_strong_enums
+    cxx_trailing_return_types
+    cxx_unicode_literals
+    cxx_user_literals
+    cxx_variadic_macros
+)
+
+target_include_directories(Catch2
+  INTERFACE
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/single_include>
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+)
+
+# provide a namespaced alias for clients to 'link' against if catch is included as a sub-project
+add_library(Catch2::Catch2 ALIAS Catch2)
+
+# Only perform the installation steps when Catch is not being used as
+# a subproject via `add_subdirectory`, or the destinations will break,
+# see https://github.com/catchorg/Catch2/issues/1373
+if (NOT_SUBPROJECT)
+    set(CATCH_CMAKE_CONFIG_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Catch2")
+
+    configure_package_config_file(
+        ${CMAKE_CURRENT_LIST_DIR}/CMake/Catch2Config.cmake.in
+        ${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake
+        INSTALL_DESTINATION
+          ${CATCH_CMAKE_CONFIG_DESTINATION}
     )
 
-    configure_file(${CMAKE_CURRENT_SOURCE_DIR}/catch.pc.in ${CMAKE_CURRENT_BINARY_DIR}/catch.pc @ONLY)
-    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/catch.pc DESTINATION ${PKGCONFIG_INSTALL_DIR})
 
-endif()
+    # create and install an export set for catch target as Catch2::Catch
+    install(
+      TARGETS
+        Catch2
+      EXPORT
+        Catch2Targets
+      DESTINATION
+        ${CMAKE_INSTALL_LIBDIR}
+    )
+
+
+    install(
+      EXPORT
+        Catch2Targets
+      NAMESPACE
+        Catch2::
+      DESTINATION
+        ${CATCH_CMAKE_CONFIG_DESTINATION}
+    )
+
+    # By default, FooConfigVersion is tied to architecture that it was
+    # generated on. Because Catch2 is header-only, it is arch-independent
+    # and thus Catch2ConfigVersion should not be tied to the architecture
+    # it was generated on.
+    #
+    # CMake does not provide a direct customization point for this in
+    # `write_basic_package_version_file`, but it can be accomplished
+    # indirectly by temporarily undefining `CMAKE_SIZEOF_VOID_P`.
+    set(CATCH2_CMAKE_SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
+    unset(CMAKE_SIZEOF_VOID_P)
+    write_basic_package_version_file(
+      "${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
+      COMPATIBILITY
+        SameMajorVersion
+    )
+    set(CMAKE_SIZEOF_VOID_P ${CATCH2_CMAKE_SIZEOF_VOID_P})
+
+    install(
+      DIRECTORY
+        "single_include/"
+      DESTINATION
+        "${CMAKE_INSTALL_INCLUDEDIR}"
+    )
+
+    install(
+      FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/Catch2Config.cmake"
+        "${CMAKE_CURRENT_BINARY_DIR}/Catch2ConfigVersion.cmake"
+      DESTINATION
+        ${CATCH_CMAKE_CONFIG_DESTINATION}
+    )
+
+    # Install documentation
+    if(CATCH_INSTALL_DOCS)
+      install(
+        DIRECTORY
+          docs/
+        DESTINATION
+          "${CMAKE_INSTALL_DOCDIR}"
+      )
+    endif()
+
+    if(CATCH_INSTALL_HELPERS)
+    # Install CMake scripts
+    install(
+      FILES
+        "contrib/ParseAndAddCatchTests.cmake"
+        "contrib/Catch.cmake"
+        "contrib/CatchAddTests.cmake"
+      DESTINATION
+        ${CATCH_CMAKE_CONFIG_DESTINATION}
+    )
+
+    # Install debugger helpers
+    install(
+      FILES
+        "contrib/gdbinit"
+        "contrib/lldbinit"
+      DESTINATION
+        ${CMAKE_INSTALL_DATAROOTDIR}/Catch2
+    )
+    endif()
+
+    ## Provide some pkg-config integration
+    set(PKGCONFIG_INSTALL_DIR
+        "${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig"
+        CACHE PATH "Path where catch2.pc is installed"
+    )
+    configure_file(
+      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/catch2.pc.in
+      ${CMAKE_CURRENT_BINARY_DIR}/catch2.pc
+      @ONLY
+    )
+    install(
+      FILES
+        "${CMAKE_CURRENT_BINARY_DIR}/catch2.pc"
+      DESTINATION
+        ${PKGCONFIG_INSTALL_DIR}
+    )
+
+endif(NOT_SUBPROJECT)
diff --git a/METADATA b/METADATA
index 03fb27c..cf98e4a 100644
--- a/METADATA
+++ b/METADATA
@@ -13,7 +13,7 @@
     type: GIT
     value: "https://github.com/catchorg/Catch2.git"
   }
-  version: "62dae592c330ab74cea30c897255ee9518639c3f"
-  last_upgrade_date { year: 2018 month: 2 day: 6 }
+  version: "v2.7.0"
+  last_upgrade_date { year: 2019 month: 3 day: 7 }
   license_type: NOTICE
 }
diff --git a/README.md b/README.md
index 1c2c03b..08095f1 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,11 @@
 [![Build Status](https://travis-ci.org/catchorg/Catch2.svg?branch=master)](https://travis-ci.org/catchorg/Catch2)
 [![Build status](https://ci.appveyor.com/api/projects/status/github/catchorg/Catch2?svg=true)](https://ci.appveyor.com/project/catchorg/catch2)
 [![codecov](https://codecov.io/gh/catchorg/Catch2/branch/master/graph/badge.svg)](https://codecov.io/gh/catchorg/Catch2)
-[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/TpIcJaLaH4WrKlhS)
+[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/byNJIivVphHo170P)
+[![Join the chat in Discord: https://discord.gg/4CWS9zD](https://img.shields.io/badge/Discord-Chat!-brightgreen.svg)](https://discord.gg/4CWS9zD)
 
-<a href="https://github.com/catchorg/Catch2/releases/download/v2.1.1/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
+
+<a href="https://github.com/catchorg/Catch2/releases/download/v2.7.0/catch.hpp">The latest version of the single header can be downloaded directly using this link</a>
 
 ## Catch2 is released!
 
@@ -32,5 +34,5 @@
 
 ## More
 * Issues and bugs can be raised on the [Issue tracker on GitHub](https://github.com/catchorg/Catch2/issues)
-* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)
+* For discussion or questions please use [the dedicated Google Groups forum](https://groups.google.com/forum/?fromgroups#!forum/catch-forum) or our [Discord](https://discord.gg/4CWS9zD)
 * See [who else is using Catch2](docs/opensource-users.md#top)
diff --git a/appveyor.yml b/appveyor.yml
index 2d68172..53f5b39 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -19,18 +19,51 @@
 
         - additional_flags: "/D_UNICODE /DUNICODE"
           wmain: 1
+          coverage: 0
+
+        # Have a coverage dimension
+        - additional_flags: ""
+          wmain: 0
+          coverage: 1
+
+        # Have an examples dimension
+        - additional_flags: ""
+          wmain: 0
+          examples: 1
+
 
 matrix:
     exclude:
         - os: Visual Studio 2015
           additional_flags: "/permissive- /std:c++latest"
 
-init:
-  - git config --global core.autocrlf input
+        - os: Visual Studio 2015
+          additional_flags: "/D_UNICODE /DUNICODE"
+
+        # Exclude unwanted coverage configurations
+        - coverage: 1
+          platform: Win32
+
+        - coverage: 1
+          os: Visual Studio 2015
+
+        - coverage: 1
+          configuration: Release
+
+        # Exclude unwanted examples configurations
+        - examples: 1
+          platform: Win32
+
+        - examples: 1
+          os: Visual Studio 2015
+
+        - examples: 1
+          configuration: Release
+
 
 install:
-  - ps: if (($env:CONFIGURATION) -eq "Debug" ) { python -m pip install codecov }
-  - ps: if (($env:CONFIGURATION) -eq "Debug" ) { .\misc\installOpenCppCoverage.ps1 }
+  - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { python -m pip --disable-pip-version-check install codecov }
+  - ps: if (($env:CONFIGURATION) -eq "Debug" -And ($env:coverage) -eq "1" ) { .\misc\installOpenCppCoverage.ps1 }
 
 # Win32 and x64 are CMake-compatible solution platform names.
 # This allows us to pass %PLATFORM% to CMake -A.
diff --git a/catch.pc.in b/catch.pc.in
deleted file mode 100644
index abd0b66..0000000
--- a/catch.pc.in
+++ /dev/null
@@ -1,6 +0,0 @@
-includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@
-
-Name: Catch
-Description: Testing library for C++
-Version: @Catch2_VERSION@
-Cflags: -I${includedir}
diff --git a/codecov.yml b/codecov.yml
index 7fd12df..94d88d8 100644
--- a/codecov.yml
+++ b/codecov.yml
@@ -6,17 +6,19 @@
     project:
       default:
         threshold: 2%
-
-codecov:
-  branch: master
-
-comment:
-  layout: "diff"
-
-coverage:
+    patch:
+      default:
+        target: 80%
   ignore:
     - "projects/SelfTest"
     - "**/catch_reporter_tap.hpp"
     - "**/catch_reporter_automake.hpp"
     - "**/catch_reporter_teamcity.hpp"
     - "**/external/clara.hpp"
+
+
+codecov:
+  branch: master
+
+comment:
+  layout: "diff"
diff --git a/conanfile.py b/conanfile.py
index fa9fdce..a7cebb9 100644
--- a/conanfile.py
+++ b/conanfile.py
@@ -1,19 +1,27 @@
 #!/usr/bin/env python
-from conans import ConanFile
+from conans import ConanFile, CMake
 
 
 class CatchConan(ConanFile):
-    name = "Catch"
-    version = "2.1.1"
+    name = "Catch2"
     description = "A modern, C++-native, header-only, framework for unit-tests, TDD and BDD"
-    author = "philsquared"
+    topics = ("conan", "catch2", "header-only", "unit-test", "tdd", "bdd")
+    url = "https://github.com/catchorg/Catch2"
+    homepage = url
+    license = "BSL-1.0"
+    exports = "LICENSE.txt"
+    exports_sources = ("single_include/*", "CMakeLists.txt", "CMake/*", "contrib/*")
     generators = "cmake"
-    exports_sources = "single_include/*"
-    url = "https://github.com/philsquared/Catch"
-    license = "Boost Software License - Version 1.0. http://www.boost.org/LICENSE_1_0.txt"
 
     def package(self):
-        self.copy(pattern="catch.hpp", src="single_include", dst="include")
+        cmake = CMake(self)
+        cmake.definitions["BUILD_TESTING"] = "OFF"
+        cmake.definitions["CATCH_INSTALL_DOCS"] = "OFF"
+        cmake.definitions["CATCH_INSTALL_HELPERS"] = "ON"
+        cmake.configure()
+        cmake.install()
+
+        self.copy(pattern="LICENSE.txt", dst="licenses")
 
     def package_id(self):
-            self.info.header_only()
+        self.info.header_only()
diff --git a/contrib/CatchAddTests.cmake b/contrib/CatchAddTests.cmake
index c68921e..2220ce3 100644
--- a/contrib/CatchAddTests.cmake
+++ b/contrib/CatchAddTests.cmake
@@ -50,14 +50,15 @@
 
 # Parse output
 foreach(line ${output})
-  # Test name; strip spaces to get just the name...
-  string(REGEX REPLACE " +" "" test "${line}")
+  set(test ${line})
+  # use escape commas to handle properly test cases with commans inside the name
+  string(REPLACE "," "\\," test_name ${test})
   # ...and add to script
   add_command(add_test
     "${prefix}${test}${suffix}"
     ${TEST_EXECUTOR}
     "${TEST_EXECUTABLE}"
-    "${test}"
+    "${test_name}"
     ${extra_args}
   )
   add_command(set_tests_properties
diff --git a/contrib/ParseAndAddCatchTests.cmake b/contrib/ParseAndAddCatchTests.cmake
index cb2846d..ff4fc66 100644
--- a/contrib/ParseAndAddCatchTests.cmake
+++ b/contrib/ParseAndAddCatchTests.cmake
@@ -39,6 +39,11 @@
 #    PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS (Default OFF)                                      #
 #    -- causes CMake to rerun when file with tests changes so that new tests will be discovered    #
 #                                                                                                  #
+# One can also set (locally) the optional variable OptionalCatchTestLauncher to precise the way    #
+# a test should be run. For instance to use test MPI, one can write                                #
+#     set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC})                 #
+# just before calling this ParseAndAddCatchTests function                                          #
+#                                                                                                  #
 #==================================================================================================#
 
 cmake_minimum_required(VERSION 2.8.8)
@@ -104,7 +109,7 @@
         # Get test type and fixture if applicable
         string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)[ \t]*\\([^,^\"]*" TestTypeAndFixture "${TestName}")
         string(REGEX MATCH "(CATCH_)?(TEST_CASE_METHOD|SCENARIO|TEST_CASE)" TestType "${TestTypeAndFixture}")
-        string(REPLACE "${TestType}(" "" TestFixture "${TestTypeAndFixture}")
+        string(REGEX REPLACE "${TestType}\\([ \t]*" "" TestFixture "${TestTypeAndFixture}")
 
         # Get string parts of test definition
         string(REGEX MATCHALL "\"+([^\\^\"]|\\\\\")+\"+" TestStrings "${TestName}")
@@ -143,6 +148,9 @@
             endif()
             string(REPLACE "]" ";" Tags "${Tags}")
             string(REPLACE "[" "" Tags "${Tags}")
+        else()
+          # unset tags variable from previous loop
+          unset(Tags)
         endif()
 
         list(APPEND Labels ${Tags})
@@ -156,7 +164,7 @@
                 break()
             endif(result)
         endforeach(label)
-        if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound})
+        if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_LESS "3.9")
             PrintDebugMessage("Skipping test \"${CTestName}\" as it has [!hide], [.] or [.foo] label")
         else()
             PrintDebugMessage("Adding test \"${CTestName}\"")
@@ -164,12 +172,22 @@
                 PrintDebugMessage("Setting labels to ${Labels}")
             endif()
 
+            # Escape commas in the test spec
+            string(REPLACE "," "\\," Name ${Name})
+
             # Add the test and set its properties
-            add_test(NAME "\"${CTestName}\"" COMMAND ${TestTarget} ${Name} ${AdditionalCatchParameters})
-            set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
-                                                    LABELS "${Labels}")
+            add_test(NAME "\"${CTestName}\"" COMMAND ${OptionalCatchTestLauncher} ${TestTarget} ${Name} ${AdditionalCatchParameters})
+            # Old CMake versions do not document VERSION_GREATER_EQUAL, so we use VERSION_GREATER with 3.8 instead
+            if(PARSE_CATCH_TESTS_NO_HIDDEN_TESTS AND ${HiddenTagFound} AND ${CMAKE_VERSION} VERSION_GREATER "3.8")
+                PrintDebugMessage("Setting DISABLED test property")
+                set_tests_properties("\"${CTestName}\"" PROPERTIES DISABLED ON)
+            else()
+                set_tests_properties("\"${CTestName}\"" PROPERTIES FAIL_REGULAR_EXPRESSION "No tests ran"
+                                                        LABELS "${Labels}")
+            endif()
         endif()
 
+
     endforeach()
 endfunction()
 
diff --git a/contrib/gdbinit b/contrib/gdbinit
new file mode 100644
index 0000000..fb3608a
--- /dev/null
+++ b/contrib/gdbinit
@@ -0,0 +1,16 @@
+#
+# This file provides a way to skip stepping into Catch code when debugging with gdb.
+#
+# With the gdb "skip" command you can tell gdb to skip files or functions during debugging.
+# see https://xaizek.github.io/2016-05-26/skipping-standard-library-in-gdb/ for an example
+#
+# Basically the following line tells gdb to skip all functions containing the
+# regexp "Catch", which matches the complete Catch namespace.
+# If you want to skip just some parts of the Catch code you can modify the
+# regexp accordingly.
+# 
+# If you want to permanently skip stepping into Catch code copy the following
+# line into your ~/.gdbinit file
+# 
+
+skip -rfu Catch
diff --git a/contrib/lldbinit b/contrib/lldbinit
new file mode 100644
index 0000000..4f13634
--- /dev/null
+++ b/contrib/lldbinit
@@ -0,0 +1,16 @@
+#
+# This file provides a way to skip stepping into Catch code when debugging with lldb.
+#
+# With the setting "target.process.thread.step-avoid-regexp" you can tell lldb
+# to skip functions matching the regexp
+#
+# Basically the following line tells lldb to skip all functions containing the
+# regexp "Catch", which matches the complete Catch namespace.
+# If you want to skip just some parts of the Catch code you can modify the
+# regexp accordingly.
+#
+# If you want to permanently skip stepping into Catch code copy the following
+# line into your ~/.lldbinit file
+#
+
+settings set target.process.thread.step-avoid-regexp Catch
\ No newline at end of file
diff --git a/docs/Readme.md b/docs/Readme.md
index be7d1cd..721880a 100644
--- a/docs/Readme.md
+++ b/docs/Readme.md
@@ -12,6 +12,8 @@
 * [Test fixtures](test-fixtures.md#top)
 * [Reporters](reporters.md#top)
 * [Event Listeners](event-listeners.md#top)
+* [Data Generators](generators.md#top)
+* [Other macros](other-macros.md#top)
 
 Fine tuning:
 * [Supplying your own main()](own-main.md#top)
@@ -20,7 +22,10 @@
 
 Running:
 * [Command line](command-line.md#top)
-* [CI and Build system integration](build-systems.md#top)
+
+Odds and ends:
+* [CMake integration](cmake-integration.md#top)
+* [CI and other miscellaneous pieces](ci-and-misc.md#top)
 
 FAQ:
 * [Why are my tests slow to compile?](slow-compiles.md#top)
@@ -31,3 +36,4 @@
 * [Open Source Projects using Catch](opensource-users.md#top)
 * [Contributing](contributing.md#top)
 * [Release Notes](release-notes.md#top)
+* [Deprecations and incoming changes](deprecations.md#top)
diff --git a/docs/assertions.md b/docs/assertions.md
index ece4e10..900fd52 100644
--- a/docs/assertions.md
+++ b/docs/assertions.md
@@ -6,10 +6,11 @@
 [Exceptions](#exceptions)<br>
 [Matcher expressions](#matcher-expressions)<br>
 [Thread Safety](#thread-safety)<br>
+[Expressions with commas](#expressions-with-commas)<br>
 
 Most test frameworks have a large collection of assertion macros to capture all possible conditional forms (```_EQUALS```, ```_NOTEQUALS```, ```_GREATER_THAN``` etc).
 
-Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxilliary macros as well. We'll describe all of these here.
+Catch is different. Because it decomposes natural C-style conditional expressions most of these forms are reduced to one or two that you will use all the time. That said there are a rich set of auxiliary macros as well. We'll describe all of these here.
 
 Most of these macros come in two forms:
 
@@ -54,33 +55,45 @@
 
 When comparing floating point numbers - especially if at least one of them has been computed - great care must be taken to allow for rounding errors and inexact representations.
 
-Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called ```Approx```. ```Approx``` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
+Catch provides a way to perform tolerant comparisons of floating point values through use of a wrapper class called `Approx`. `Approx` can be used on either side of a comparison expression. It overloads the comparisons operators to take a tolerance into account. Here's a simple example:
 
-```
+```cpp
 REQUIRE( performComputation() == Approx( 2.1 ) );
 ```
 
-This way `Approx` is constructed with reasonable defaults, covering most simple cases of rounding errors. If these are insufficient, each `Approx` instance has 3 tuning knobs, that can be used to customize it for your computation.
+Catch also provides a UDL for `Approx`; `_a`. It resides in
+the `Catch::literals` namespace and can be used like so:
+```cpp
+using namespace Catch::literals;
+REQUIRE( performComputation() == 2.1_a );
+```
 
-* __epsilon__ - epsilon serves to set the percentage by which a result can be erroneous, before it is rejected. By default set to `std::numeric_limits<float>::epsilon()*100`.
-* __margin__ - margin serves to set the the absolute value by which a result can be erroneous before it is rejected. By default set to `0.0`.
-* __scale__ - scale serves to adjust the epsilon's multiplicator. By default set to `0.0`.
+`Approx` is constructed with defaults that should cover most simple cases.
+For the more complex cases, `Approx` provides 3 customization points:
+
+* __epsilon__ - epsilon serves to set the coefficient by which a result
+can differ from `Approx`'s value before it is rejected.
+_By default set to `std::numeric_limits<float>::epsilon()*100`._
+* __margin__ - margin serves to set the the absolute value by which
+a result can differ from `Approx`'s value before it is rejected.
+_By default set to `0.0`._
+* __scale__ - scale is used to change the magnitude of `Approx` for relative check.
+_By default set to `0.0`._
 
 #### epsilon example
 ```cpp
 Approx target = Approx(100).epsilon(0.01);
 100.0 == target; // Obviously true
 200.0 == target; // Obviously still false
-100.5 == target; // True, because we set target to allow up to 1% error
+100.5 == target; // True, because we set target to allow up to 1% difference
 ```
 
 #### margin example
-_Margin check is used only if the relative (epsilon and scale based) check fails._
 ```cpp
 Approx target = Approx(100).margin(5);
 100.0 == target; // Obviously true
 200.0 == target; // Obviously still false
-104.0 == target; // True, because we set target to allow absolute error up to 5
+104.0 == target; // True, because we set target to allow absolute difference of at most 5
 ```
 
 #### scale
@@ -155,6 +168,34 @@
 Currently assertions in Catch are not thread safe.
 For more details, along with workarounds, see the section on [the limitations page](limitations.md#thread-safe-assertions).
 
+## Expressions with commas
+
+Because the preprocessor parses code using different rules than the
+compiler, multiple-argument assertions (e.g. `REQUIRE_THROWS_AS`) have
+problems with commas inside the provided expressions. As an example
+`REQUIRE_THROWS_AS(std::pair<int, int>(1, 2), std::invalid_argument);`
+will fail to compile, because the preprocessor sees 3 arguments provided,
+but the macro accepts only 2. There are two possible workarounds.
+
+1) Use typedef:
+```cpp
+using int_pair = std::pair<int, int>;
+REQUIRE_THROWS_AS(int_pair(1, 2), std::invalid_argument);
+```
+
+This solution is always applicable, but makes the meaning of the code
+less clear.
+
+2) Parenthesize the expression:
+```cpp
+TEST_CASE_METHOD((Fixture<int, int>), "foo", "[bar]") {
+    SUCCEED();
+}
+```
+
+This solution is not always applicable, because it might require extra
+changes on the Catch's side to work.
+
 ---
 
 [Home](Readme.md#top)
diff --git a/docs/build-systems.md b/docs/build-systems.md
deleted file mode 100644
index 2873bc6..0000000
--- a/docs/build-systems.md
+++ /dev/null
@@ -1,175 +0,0 @@
-<a id="top"></a>
-# CI and build system integration
-
-Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
-
-## Continuous Integration systems
-
-Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP and Automake reporters).
-
-Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
-
-### XML Reporter
-```-r xml``` 
-
-The XML Reporter writes in an XML format that is specific to Catch. 
-
-The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
-
-The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could convert it to, say, HTML - although this loses the streaming advantage, of course.
-
-### JUnit Reporter
-```-r junit```
-
-The JUnit Reporter writes in an XML format that mimics the JUnit ANT schema.
-
-The advantage of this format is that the JUnit Ant schema is widely understood by most build servers and so can usually be consumed with no additional work.
-
-The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
-
-## Other reporters
-Other reporters are not part of the single-header distribution and need
-to be downloaded and included separately. All reporters are stored in
-`single_include` directory in the git repository, and are named
-`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you
-need to download `single_include/catch_reporter_teamcity.hpp` and include
-it after Catch itself.
-
-```cpp
-#define CATCH_CONFIG_MAIN
-#include "catch.hpp"
-#include "catch_reporter_teamcity.hpp"
-```
-
-### TeamCity Reporter
-```-r teamcity```
-
-The TeamCity Reporter writes TeamCity service messages to stdout. In order to be able to use this reporter an additional header must also be included.
-
-Being specific to TeamCity this is the best reporter to use with it - but it is completely unsuitable for any other purpose. It is a streaming format (it writes as it goes) - although test results don't appear in the TeamCity interface until the completion of a suite (usually the whole test run).
-
-### Automake Reporter
-```-r automake```
-
-The Automake Reporter writes out the [meta tags](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html#Log-files-generation-and-test-results-recording) expected by automake via `make check`.
-
-### TAP (Test Anything Protocol) Reporter
-```-r tap```
-
-Because of the incremental nature of Catch's test suites and ability to run specific tests, our implementation of TAP reporter writes out the number of tests in a suite last.
-
-## Low-level tools
-
-### Precompiled headers (PCHs)
-
-Catch offers prototypal support for being included in precompiled headers, but because of its single-header nature it does need some actions by the user:
-* The precompiled header needs to define `CATCH_CONFIG_ALL_PARTS`
-* The implementation file needs to
-  * undefine `TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED`
-  * define `CATCH_CONFIG_IMPL_ONLY`
-  * define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`
-  * include "catch.hpp" again
-
-
-### CMake
-
-In general we recommend "vendoring" Catch's single-include releases inside your own repository. If you do this, the following example shows a minimal CMake project:
-```CMake
-cmake_minimum_required(VERSION 3.0)
-
-project(cmake_test)
-
-# Prepare "Catch" library for other executables
-set(CATCH_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/catch)
-add_library(Catch INTERFACE)
-target_include_directories(Catch INTERFACE ${CATCH_INCLUDE_DIR})
-
-# Make test executable
-set(TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp)
-add_executable(tests ${TEST_SOURCES})
-target_link_libraries(tests Catch)
-```
-Note that it assumes that the path to the Catch's header is `catch/catch.hpp` from the `CMakeLists.txt` file.
-
-
-You can also use the following CMake snippet to automatically fetch the entire Catch repository from github and configure it as an external project:
-```CMake
-cmake_minimum_required(VERSION 2.8.8)
-project(catch_builder CXX)
-include(ExternalProject)
-find_package(Git REQUIRED)
-
-ExternalProject_Add(
-    catch
-    PREFIX ${CMAKE_BINARY_DIR}/catch
-    GIT_REPOSITORY https://github.com/philsquared/Catch.git
-    TIMEOUT 10
-    UPDATE_COMMAND ${GIT_EXECUTABLE} pull
-    CONFIGURE_COMMAND ""
-    BUILD_COMMAND ""
-    INSTALL_COMMAND ""
-    LOG_DOWNLOAD ON
-   )
-
-# Expose required variable (CATCH_INCLUDE_DIR) to parent scope
-ExternalProject_Get_Property(catch source_dir)
-set(CATCH_INCLUDE_DIR ${source_dir}/single_include CACHE INTERNAL "Path to include folder for Catch")
-```
-
-If you put it in, e.g., `${PROJECT_SRC_DIR}/${EXT_PROJECTS_DIR}/catch/`, you can use it in your project by adding the following to your root CMake file:
-
-```CMake
-# Includes Catch in the project:
-add_subdirectory(${EXT_PROJECTS_DIR}/catch)
-include_directories(${CATCH_INCLUDE_DIR} ${COMMON_INCLUDES})
-enable_testing(true)  # Enables unit-testing.
-```
-
-The advantage of this approach is that you can always automatically update Catch to the latest release. The disadvantage is that it means bringing in lot more than you need.
-
-
-### Automatic test registration
-We provide 2 CMake scripts that can automatically register Catch-based
-tests with CTest,
-  * `contrib/ParseAndAddCatchTests.cmake`
-  * `contrib/CatchAddTests.cmake`
-
-The first is based on parsing the test implementation files, and attempts
-to register all `TEST_CASE`s using their tags as labels. This means that
-these:
-
-```cpp
-TEST_CASE("Test1", "[unit]") {
-    int a = 1;
-    int b = 2;
-    REQUIRE(a == b);
-}
-
-TEST_CASE("Test2") {
-    int a = 1;
-    int b = 2;
-    REQUIRE(a == b);
-}
-
-TEST_CASE("Test3", "[a][b][c]") {
-    int a = 1;
-    int b = 2;
-    REQUIRE(a == b);
-}
-```
-would be registered as 3 tests, `Test1`, `Test2` and `Test3`,
-and 4 CTest labels would be created, `a`, `b`, `c` and `unit`.
-
-
-The second is based on parsing the output of a Catch binary given
-`--list-test-names-only`. This means that it deals with inactive
-(e.g. commented-out) tests better, but requires CMake 3.10 for full
-functionality.
-
-### CodeCoverage module (GCOV, LCOV...)
-
-If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
-
----
-
-[Home](Readme.md#top)
diff --git a/docs/ci-and-misc.md b/docs/ci-and-misc.md
new file mode 100644
index 0000000..8c33087
--- /dev/null
+++ b/docs/ci-and-misc.md
@@ -0,0 +1,108 @@
+<a id="top"></a>
+# CI and other odd pieces
+
+**Contents**<br>
+[Continuous Integration systems](#continuous-integration-systems)<br>
+[Other reporters](#other-reporters)<br>
+[Low-level tools](#low-level-tools)<br>
+[CMake](#cmake)<br>
+
+This page talks about how Catch integrates with Continuous Integration 
+Build Systems may refer to low-level tools, like CMake, or larger systems that run on servers, like Jenkins or TeamCity. This page will talk about both.
+
+## Continuous Integration systems
+
+Probably the most important aspect to using Catch with a build server is the use of different reporters. Catch comes bundled with three reporters that should cover the majority of build servers out there - although adding more for better integration with some is always a possibility (currently we also offer TeamCity, TAP and Automake reporters).
+
+Two of these reporters are built in (XML and JUnit) and the third (TeamCity) is included as a separate header. It's possible that the other two may be split out in the future too - as that would make the core of Catch smaller for those that don't need them.
+
+### XML Reporter
+```-r xml``` 
+
+The XML Reporter writes in an XML format that is specific to Catch. 
+
+The advantage of this format is that it corresponds well to the way Catch works (especially the more unusual features, such as nested sections) and is a fully streaming format - that is it writes output as it goes, without having to store up all its results before it can start writing.
+
+The disadvantage is that, being specific to Catch, no existing build servers understand the format natively. It can be used as input to an XSLT transformation that could convert it to, say, HTML - although this loses the streaming advantage, of course.
+
+### JUnit Reporter
+```-r junit```
+
+The JUnit Reporter writes in an XML format that mimics the JUnit ANT schema.
+
+The advantage of this format is that the JUnit Ant schema is widely understood by most build servers and so can usually be consumed with no additional work.
+
+The disadvantage is that this schema was designed to correspond to how JUnit works - and there is a significant mismatch with how Catch works. Additionally the format is not streamable (because opening elements hold counts of failed and passing tests as attributes) - so the whole test run must complete before it can be written.
+
+## Other reporters
+Other reporters are not part of the single-header distribution and need
+to be downloaded and included separately. All reporters are stored in
+`single_include` directory in the git repository, and are named
+`catch_reporter_*.hpp`. For example, to use the TeamCity reporter you
+need to download `single_include/catch_reporter_teamcity.hpp` and include
+it after Catch itself.
+
+```cpp
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+#include "catch_reporter_teamcity.hpp"
+```
+
+### TeamCity Reporter
+```-r teamcity```
+
+The TeamCity Reporter writes TeamCity service messages to stdout. In order to be able to use this reporter an additional header must also be included.
+
+Being specific to TeamCity this is the best reporter to use with it - but it is completely unsuitable for any other purpose. It is a streaming format (it writes as it goes) - although test results don't appear in the TeamCity interface until the completion of a suite (usually the whole test run).
+
+### Automake Reporter
+```-r automake```
+
+The Automake Reporter writes out the [meta tags](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html#Log-files-generation-and-test-results-recording) expected by automake via `make check`.
+
+### TAP (Test Anything Protocol) Reporter
+```-r tap```
+
+Because of the incremental nature of Catch's test suites and ability to run specific tests, our implementation of TAP reporter writes out the number of tests in a suite last.
+
+## Low-level tools
+
+### Precompiled headers (PCHs)
+
+Catch offers prototypal support for being included in precompiled headers, but because of its single-header nature it does need some actions by the user:
+* The precompiled header needs to define `CATCH_CONFIG_ALL_PARTS`
+* The implementation file needs to
+  * undefine `TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED`
+  * define `CATCH_CONFIG_IMPL_ONLY`
+  * define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`
+  * include "catch.hpp" again
+
+
+### CodeCoverage module (GCOV, LCOV...)
+
+If you are using GCOV tool to get testing coverage of your code, and are not sure how to integrate it with CMake and Catch, there should be an external example over at https://github.com/fkromer/catch_cmake_coverage
+
+
+### pkg-config
+
+Catch2 provides a rudimentary pkg-config integration, by registering itself
+under the name `catch2`. This means that after Catch2 is installed, you
+can use `pkg-config` to get its include path: `pkg-config --cflags catch2`.
+
+### gdb and lldb scripts
+
+Catch2's `contrib` folder also contains two simple debugger scripts,
+`gdbinit` for `gdb` and `lldbinit` for `lldb`. If loaded into their
+respective debugger, these will tell it to step over Catch2's internals
+when stepping through code.
+
+
+## CMake
+
+[As it has been getting kinda long, the documentation of Catch2's
+integration with CMake has been moved to its own page.](cmake-integration.md#top)
+
+
+---
+
+[Home](Readme.md#top)
diff --git a/docs/cmake-integration.md b/docs/cmake-integration.md
new file mode 100644
index 0000000..246e7f0
--- /dev/null
+++ b/docs/cmake-integration.md
@@ -0,0 +1,226 @@
+<a id="top"></a>
+# CMake integration
+
+**Contents**<br>
+[CMake target](#cmake-target)<br>
+[Automatic test registration](#automatic-test-registration)<br>
+[CMake project options](#cmake-project-options)<br>
+[Installing Catch2 from git repository](#installing-catch2-from-git-repository)<br>
+
+Because we use CMake to build Catch2, we also provide a couple of
+integration points for our users.
+
+1) Catch2 exports a (namespaced) CMake target
+2) Catch2's repository contains CMake scripts for automatic registration
+of `TEST_CASE`s in CTest
+
+## CMake target
+
+Catch2's CMake build exports an interface target `Catch2::Catch2`. Linking
+against it will add the proper include path and all necessary capabilities
+to the resulting binary.
+
+This means that if Catch2 has been installed on the system, it should be
+enough to do:
+```cmake
+find_package(Catch2 REQUIRED)
+target_link_libraries(tests Catch2::Catch2)
+```
+
+
+This target is also provided when Catch2 is used as a subdirectory.
+Assuming that Catch2 has been cloned to `lib/Catch2`:
+```cmake
+add_subdirectory(lib/Catch2)
+target_link_libraries(tests Catch2::Catch2)
+```
+
+## Automatic test registration
+
+Catch2's repository also contains two CMake scripts that help users
+with automatically registering their `TEST_CASE`s with CTest. They
+can be found in the `contrib` folder, and are
+
+1) `Catch.cmake` (and its dependency `CatchAddTests.cmake`)
+2) `ParseAndAddCatchTests.cmake`
+
+If Catch2 has been installed in system, both of these can be used after
+doing `find_package(Catch2 REQUIRED)`. Otherwise you need to add them
+to your CMake module path.
+
+### `Catch.cmake` and `AddCatchTests.cmake`
+
+`Catch.cmake` provides function `catch_discover_tests` to get tests from
+a target. This function works by running the resulting executable with
+`--list-test-names-only` flag, and then parsing the output to find all
+existing tests.
+
+#### Usage
+```cmake
+cmake_minimum_required(VERSION 3.5)
+
+project(baz LANGUAGES CXX VERSION 0.0.1)
+
+find_package(Catch2 REQUIRED)
+add_executable(foo test.cpp)
+target_link_libraries(foo Catch2::Catch2)
+
+include(CTest)
+include(Catch)
+catch_discover_tests(foo)
+```
+
+
+#### Customization
+`catch_discover_tests` can be given several extra argumets:
+```cmake
+catch_discover_tests(target
+                     [TEST_SPEC arg1...]
+                     [EXTRA_ARGS arg1...]
+                     [WORKING_DIRECTORY dir]
+                     [TEST_PREFIX prefix]
+                     [TEST_SUFFIX suffix]
+                     [PROPERTIES name1 value1...]
+                     [TEST_LIST var]
+)
+```
+
+* `TEST_SPEC arg1...`
+
+Specifies test cases, wildcarded test cases, tags and tag expressions to
+pass to the Catch executable alongside the `--list-test-names-only` flag.
+
+
+* `EXTRA_ARGS arg1...`
+
+Any extra arguments to pass on the command line to each test case.
+
+
+* `WORKING_DIRECTORY dir`
+
+Specifies the directory in which to run the discovered test cases.  If this
+option is not provided, the current binary directory is used.
+
+
+* `TEST_PREFIX prefix`
+
+Specifies a _prefix_ to be added to the name of each discovered test case.
+This can be useful when the same test executable is being used in multiple
+calls to `catch_discover_tests()`, with different `TEST_SPEC` or `EXTRA_ARGS`.
+
+
+* `TEST_SUFFIX suffix`
+
+Same as `TEST_PREFIX`, except it specific the _suffix_ for the test names.
+Both `TEST_PREFIX` and `TEST_SUFFIX` can be specified at the same time.
+
+
+* `PROPERTIES name1 value1...`
+
+Specifies additional properties to be set on all tests discovered by this
+invocation of `catch_discover_tests`.
+
+
+* `TEST_LIST var`
+
+Make the list of tests available in the variable `var`, rather than the
+default `<target>_TESTS`.  This can be useful when the same test
+executable is being used in multiple calls to `catch_discover_tests()`.
+Note that this variable is only available in CTest.
+
+
+### `ParseAndAddCatchTests.cmake`
+
+`ParseAndAddCatchTests` works by parsing all implementation files
+associated with the provided target, and registering them via CTest's
+`add_test`. This approach has some limitations, such as the fact that
+commented-out tests will be registered anyway.
+
+
+#### Usage
+
+```cmake
+cmake_minimum_required(VERSION 3.5)
+
+project(baz LANGUAGES CXX VERSION 0.0.1)
+
+find_package(Catch2 REQUIRED)
+add_executable(foo test.cpp)
+target_link_libraries(foo Catch2::Catch2)
+
+include(CTest)
+include(ParseAndAddCatchTests)
+ParseAndAddCatchTests(foo)
+```
+
+
+#### Customization
+
+`ParseAndAddCatchTests` provides some customization points:
+* `PARSE_CATCH_TESTS_VERBOSE` -- When `ON`, the script prints debug
+messages. Defaults to `OFF`.
+* `PARSE_CATCH_TESTS_NO_HIDDEN_TESTS` -- When `ON`, hidden tests (tests
+tagged with any of `[!hide]`, `[.]` or `[.foo]`) will not be registered.
+Defaults to `OFF`.
+* `PARSE_CATCH_TESTS_ADD_FIXTURE_IN_TEST_NAME` -- When `ON`, adds fixture
+class name to the test name in CTest. Defaults to `ON`.
+* `PARSE_CATCH_TESTS_ADD_TARGET_IN_TEST_NAME` -- When `ON`, adds target
+name to the test name in CTest. Defaults to `ON`.
+* `PARSE_CATCH_TESTS_ADD_TO_CONFIGURE_DEPENDS` -- When `ON`, adds test
+file to `CMAKE_CONFIGURE_DEPENDS`. This means that the CMake configuration
+step will be re-ran when the test files change, letting new tests be
+automatically discovered. Defaults to `OFF`.
+
+
+Optionally, one can specify a launching command to run tests by setting the
+variable `OptionalCatchTestLauncher` before calling `ParseAndAddCatchTests`. For
+instance to run some tests using `MPI` and other sequentially, one can write
+```cmake
+set(OptionalCatchTestLauncher ${MPIEXEC} ${MPIEXEC_NUMPROC_FLAG} ${NUMPROC})
+ParseAndAddCatchTests(mpi_foo)
+unset(OptionalCatchTestLauncher)
+ParseAndAddCatchTests(bar)
+```
+
+## CMake project options
+
+Catch2's CMake project also provides some options for other projects
+that consume it. These are
+
+* `CATCH_BUILD_TESTING` -- When `ON`, Catch2's SelfTest project will be
+built. Defaults to `ON`. Note that Catch2 also obeys `BUILD_TESTING` CMake
+variable, so _both_ of them need to be `ON` for the SelfTest to be built,
+and either of them can be set to `OFF` to disable building SelfTest.
+* `CATCH_BUILD_EXAMPLES` -- When `ON`, Catch2's usage examples will be
+built. Defaults to `OFF`.
+* `CATCH_INSTALL_DOCS` -- When `ON`, Catch2's documentation will be
+included in the installation. Defaults to `ON`.
+* `CATCH_INSTALL_HELPERS` -- When `ON`, Catch2's contrib folder will be
+included in the installation. Defaults to `ON`.
+* `BUILD_TESTING` -- When `ON` and the project is not used as a subproject,
+Catch2's test binary will be built. Defaults to `ON`.
+
+
+## Installing Catch2 from git repository
+
+If you cannot install Catch2 from a package manager (e.g. Ubuntu 16.04
+provides catch only in version 1.2.0) you might want to install it from
+the repository instead. Assuming you have enough rights, you can just
+install it to the default location, like so:
+```
+$ git clone https://github.com/catchorg/Catch2.git
+$ cd Catch2
+$ cmake -Bbuild -H. -DBUILD_TESTING=OFF
+$ sudo cmake --build build/ --target install
+```
+
+If you do not have superuser rights, you will also need to specify
+[CMAKE_INSTALL_PREFIX](https://cmake.org/cmake/help/latest/variable/CMAKE_INSTALL_PREFIX.html)
+when configuring the build, and then modify your calls to
+[find_package](https://cmake.org/cmake/help/latest/command/find_package.html)
+accordingly.
+
+
+---
+
+[Home](Readme.md#top)
diff --git a/docs/command-line.md b/docs/command-line.md
index 8afcb7d..fc63fe8 100644
--- a/docs/command-line.md
+++ b/docs/command-line.md
@@ -24,6 +24,7 @@
 [Usage](#usage)<br>
 [Specify the section to run](#specify-the-section-to-run)<br>
 [Filenames as tags](#filenames-as-tags)<br>
+[Override output colouring](#override-output-colouring)<br>
 
 Catch works quite nicely without any command line options at all - but for those times when you want greater control the following options are available.
 Click one of the followings links to take you straight to that option - or scroll on to browse the available options.
@@ -57,6 +58,7 @@
 <a href="#libidentify">                                 `    --libidentify`</a><br />
 <a href="#wait-for-keypress">                           `    --wait-for-keypress`</a><br />
 <a href="#benchmark-resolution-multiple">               `    --benchmark-resolution-multiple`</a><br />
+<a href="#use-colour">                                  `    --use-colour`</a><br />
 
 </br>
 
@@ -78,7 +80,7 @@
 
 Test specs are case insensitive.
 
-If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precendence, however.
+If a spec is prefixed with `exclude:` or the `~` character then the pattern matches an exclusion. This means that tests matching the pattern are excluded from the set - even if a prior inclusion spec included them. Subsequent inclusion specs will take precedence, however.
 Inclusions and exclusions are evaluated in left-to-right order.
 
 Test case examples:
@@ -94,7 +96,7 @@
 </pre>
 
 Names within square brackets are interpreted as tags.
-A series of tags form an AND expression wheras a comma-separated sequence forms an OR expression. e.g.:
+A series of tags form an AND expression whereas a comma-separated sequence forms an OR expression. e.g.:
 
 <pre>[one][two],[three]</pre>
 This matches all tests tagged `[one]` and `[two]`, as well as all tests tagged `[three]`
@@ -122,7 +124,9 @@
 ## Breaking into the debugger
 <pre>-b, --break</pre>
 
-In some IDEs (currently XCode and Visual Studio) it is possible for Catch to break into the debugger on a test failure. This can be very helpful during debug sessions - especially when there is more than one path through a particular test.
+Under most debuggers Catch2 is capable of automatically breaking on a test
+failure. This allows the user to see the current state of the test during
+failure.
 
 <a id="showing-results-for-successful-tests"></a>
 ## Showing results for successful tests
@@ -192,9 +196,16 @@
 ## Warnings
 <pre>-w, --warn &lt;warning name></pre>
 
-Enables reporting of warnings (only one, at time of this writing). If a warning is issued it fails the test.
+Enables reporting of suspicious test states. There are currently two
+available warnings
 
-The ony available warning, presently, is ```NoAssertions```. This warning fails a test case, or (leaf) section if no assertions (```REQUIRE```/ ```CHECK``` etc) are encountered.
+```
+    NoAssertions   // Fail test case / leaf section if no assertions
+                   // (e.g. `REQUIRE`) is encountered.
+    NoTests        // Return non-zero exit code when no test cases were run
+                   // Also calls reporter's noMatchingTestCases method
+```
+
 
 <a id="reporting-timings"></a>
 ## Reporting timings
@@ -262,7 +273,7 @@
 
 When running benchmarks the clock resolution is estimated. Benchmarks are then run for exponentially increasing
 numbers of iterations until some multiple of the estimated resolution is exceed. By default that multiple is 100, but 
-it can be overriden here.
+it can be overridden here.
 
 <a id="usage"></a>
 ## Usage
@@ -322,6 +333,16 @@
 
 So, for example,  tests within the file `~\Dev\MyProject\Ferrets.cpp` would be tagged `[#Ferrets]`.
 
+<a id="use-colour"></a>
+## Override output colouring
+<pre>--use-colour &lt;yes|no|auto&gt;</pre>
+
+Catch colours output for terminals, but omits colouring when it detects that
+output is being sent to a pipe. This is done to avoid interfering with automated
+processing of output.
+
+`--use-colour yes` forces coloured output, `--use-colour no` disables coloured
+output. The default behaviour is `--use-colour auto`.
 
 ---
 
diff --git a/docs/commercial-users.md b/docs/commercial-users.md
index e4d789f..4f98f75 100644
--- a/docs/commercial-users.md
+++ b/docs/commercial-users.md
@@ -13,5 +13,7 @@
 [issue](https://github.com/philsquared/Catch/issues), or on the [forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum).
  
  - Bloomberg
+ - [Bloomlife](https://bloomlife.com)
  - NASA
  - [Inscopix Inc.](https://www.inscopix.com/)
+ - [Makimo](https://makimo.pl/)
diff --git a/docs/configuration.md b/docs/configuration.md
index 3e59e76..1c94481 100644
--- a/docs/configuration.md
+++ b/docs/configuration.md
@@ -3,13 +3,19 @@
 
 **Contents**<br>
 [main()/ implementation](#main-implementation)<br>
+[Reporter / Listener interfaces](#reporter--listener-interfaces)<br>
 [Prefixing Catch macros](#prefixing-catch-macros)<br>
 [Terminal colour](#terminal-colour)<br>
 [Console width](#console-width)<br>
 [stdout](#stdout)<br>
+[Fallback stringifier](#fallback-stringifier)<br>
+[Default reporter](#default-reporter)<br>
+[C++11 toggles](#c11-toggles)<br>
+[C++17 toggles](#c17-toggles)<br>
 [Other toggles](#other-toggles)<br>
 [Windows header clutter](#windows-header-clutter)<br>
 [Enabling stringification](#enabling-stringification)<br>
+[Disabling exceptions](#disabling-exceptions)<br>
 
 Catch is designed to "just work" as much as possible. For most people the only configuration needed is telling Catch which source file should host all the implementation code (```CATCH_CONFIG_MAIN```).
 
@@ -17,14 +23,14 @@
 
 ## main()/ implementation
 
-	CATCH_CONFIG_MAIN	// Designates this as implementation file and defines main()
-	CATCH_CONFIG_RUNNER	// Designates this as implementation file
+    CATCH_CONFIG_MAIN      // Designates this as implementation file and defines main()
+    CATCH_CONFIG_RUNNER    // Designates this as implementation file
 
 Although Catch is header only it still, internally, maintains a distinction between interface headers and headers that contain implementation. Only one source file in your test project should compile the implementation headers and this is controlled through the use of one of these macros - one of these identifiers should be defined before including Catch in *exactly one implementation file in your project*.
 
-# Reporter / Listener interfaces
+## Reporter / Listener interfaces
 
-    CATCH_CONFIG_EXTERNAL_INTERFACES  // Brings in neccessary headers for Reporter/Listener implementation
+    CATCH_CONFIG_EXTERNAL_INTERFACES  // Brings in necessary headers for Reporter/Listener implementation
 
 Brings in various parts of Catch that are required for user defined Reporters and Listeners. This means that new Reporters and Listeners can be defined in this file as well as in the main file.
 
@@ -32,16 +38,16 @@
 
 ## Prefixing Catch macros
 
-	CATCH_CONFIG_PREFIX_ALL
+    CATCH_CONFIG_PREFIX_ALL
 
 To keep test code clean and uncluttered Catch uses short macro names (e.g. ```TEST_CASE``` and ```REQUIRE```). Occasionally these may conflict with identifiers from platform headers or the system under test. In this case the above identifier can be defined. This will cause all the Catch user macros to be prefixed with ```CATCH_``` (e.g. ```CATCH_TEST_CASE``` and ```CATCH_REQUIRE```).
 
 
 ## Terminal colour
 
-	CATCH_CONFIG_COLOUR_NONE	// completely disables all text colouring
-	CATCH_CONFIG_COLOUR_WINDOWS	// forces the Win32 console API to be used
-	CATCH_CONFIG_COLOUR_ANSI	// forces ANSI colour codes to be used
+    CATCH_CONFIG_COLOUR_NONE      // completely disables all text colouring
+    CATCH_CONFIG_COLOUR_WINDOWS   // forces the Win32 console API to be used
+    CATCH_CONFIG_COLOUR_ANSI      // forces ANSI colour codes to be used
 
 Yes, I am English, so I will continue to spell "colour" with a 'u'.
 
@@ -55,24 +61,81 @@
 
 ## Console width
 
-	CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
+    CATCH_CONFIG_CONSOLE_WIDTH = x // where x is a number
 
 Catch formats output intended for the console to fit within a fixed number of characters. This is especially important as indentation is used extensively and uncontrolled line wraps break this.
 By default a console width of 80 is assumed but this can be controlled by defining the above identifier to be a different value.
 
 ## stdout
 
-	CATCH_CONFIG_NOSTDOUT
+    CATCH_CONFIG_NOSTDOUT
 
-Catch does not use ```std::cout```, ```std::cerr``` and ```std::clog``` directly but gets them from ```Catch::cout()```, ```Catch::cerr()``` and ```Catch::clog``` respectively. If the above identifier is defined these functions are left unimplemented and you must implement them yourself. Their signatures are:
+To support platforms that do not provide `std::cout`, `std::cerr` and
+`std::clog`, Catch does not usem the directly, but rather calls
+`Catch::cout`, `Catch::cerr` and `Catch::clog`. You can replace their
+implementation by defining `CATCH_CONFIG_NOSTDOUT` and implementing
+them yourself, their signatures are:
 
     std::ostream& cout();
     std::ostream& cerr();
     std::ostream& clog();
 
-This can be useful on certain platforms that do not provide the standard iostreams, such as certain embedded systems.
+[You can see an example of replacing these functions here.](
+../examples/231-Cfg-OutputStreams.cpp)
 
 
+## Fallback stringifier
+
+By default, when Catch's stringification machinery has to stringify
+a type that does not specialize `StringMaker`, does not overload `operator<<`,
+is not an enumeration and is not a range, it uses `"{?}"`. This can be
+overriden by defining `CATCH_CONFIG_FALLBACK_STRINGIFIER` to name of a
+function that should perform the stringification instead.
+
+All types that do not provide `StringMaker` specialization or `operator<<`
+overload will be sent to this function (this includes enums and ranges).
+The provided function must return `std::string` and must accept any type,
+e.g. via overloading.
+
+_Note that if the provided function does not handle a type and this type
+requires to be stringified, the compilation will fail._
+
+
+## Default reporter
+
+Catch's default reporter can be changed by defining macro
+`CATCH_CONFIG_DEFAULT_REPORTER` to string literal naming the desired
+default reporter.
+
+This means that defining `CATCH_CONFIG_DEFAULT_REPORTER` to `"console"`
+is equivalent with the out-of-the-box experience.
+
+
+## C++11 toggles
+
+    CATCH_CONFIG_CPP11_TO_STRING // Use `std::to_string`
+
+Because we support platforms whose standard library does not contain
+`std::to_string`, it is possible to force Catch to use a workaround
+based on `std::stringstream`. On platforms other than Android,
+the default is to use `std::to_string`. On Android, the default is to
+use the `stringstream` workaround. As always, it is possible to override
+Catch's selection, by defining either `CATCH_CONFIG_CPP11_TO_STRING` or
+`CATCH_CONFIG_NO_CPP11_TO_STRING`.
+
+
+## C++17 toggles
+
+    CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS  // Use std::uncaught_exceptions instead of std::uncaught_exception
+    CATCH_CONFIG_CPP17_STRING_VIEW          // Provide StringMaker specialization for std::string_view
+    CATCH_CONFIG_CPP17_VARIANT              // Override C++17 detection for CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+
+Catch contains basic compiler/standard detection and attempts to use
+some C++17 features whenever appropriate. This automatic detection
+can be manually overridden in both directions, that is, a feature
+can be enabled by defining the macro in the table above, and disabled
+by using `_NO_` in the macro, e.g. `CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS`.
+
 
 ## Other toggles
 
@@ -84,6 +147,8 @@
     CATCH_CONFIG_WINDOWS_CRTDBG             // Enable leak checking using Windows's CRT Debug Heap
     CATCH_CONFIG_DISABLE_STRINGIFICATION    // Disable stringifying the original expression
     CATCH_CONFIG_DISABLE                    // Disables assertions and test case registration
+    CATCH_CONFIG_WCHAR                      // Enables use of wchart_t
+    CATCH_CONFIG_EXPERIMENTAL_REDIRECT      // Enables the new (experimental) way of capturing stdout/stderr
 
 Currently Catch enables `CATCH_CONFIG_WINDOWS_SEH` only when compiled with MSVC, because some versions of MinGW do not have the necessary Win32 API support.
 
@@ -91,14 +156,22 @@
 
 `CATCH_CONFIG_WINDOWS_CRTDBG` is off by default. If enabled, Windows's CRT is used to check for memory leaks, and displays them after the tests finish running.
 
-These toggles can be disabled by using `_NO_` form of the toggle, e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
+`CATCH_CONFIG_WCHAR` is on by default, but can be disabled. Currently
+it is only used in support for DJGPP cross-compiler.
+
+With the exception of `CATCH_CONFIG_EXPERIMENTAL_REDIRECT`,
+these toggles can be disabled by using `_NO_` form of the toggle,
+e.g. `CATCH_CONFIG_NO_WINDOWS_SEH`.
 
 ### `CATCH_CONFIG_FAST_COMPILE`
-Defining this flag speeds up compilation of test files by ~20%, by making 2 changes:
-* The `-b` (`--break`) flag no longer makes Catch break into debugger in the same stack frame as the failed test, but rather in a stack frame *below*.
-* Non-exception family of macros ({`REQUIRE`,`CHECK`}{`_`,`_FALSE`, `_FALSE`}, no longer use local try-cache block. This disables exception translation, but should not lead to false negatives.
+This compile-time flag speeds up compilation of assertion macros by ~20%,
+by disabling the generation of assertion-local try-catch blocks for
+non-exception family of assertion macros ({`REQUIRE`,`CHECK`}{``,`_FALSE`, `_THAT`}).
+This disables translation of exceptions thrown under these assertions, but
+should not lead to false negatives.
 
-`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined, in all translation units that are linked into single test binary, or the behaviour of setting `-b` flag and throwing unexpected exceptions will be unpredictable.
+`CATCH_CONFIG_FAST_COMPILE` has to be either defined, or not defined,
+in all translation units that are linked into single test binary.
 
 ### `CATCH_CONFIG_DISABLE_MATCHERS`
 When `CATCH_CONFIG_DISABLE_MATCHERS` is defined, all mentions of Catch's Matchers are ifdef-ed away from the translation unit. Doing so will speed up compilation of that TU.
@@ -127,12 +200,48 @@
 
 By default, Catch does not stringify some types from the standard library. This is done to avoid dragging in various standard library headers by default. However, Catch does contain these and can be configured to provide them, using these macros:
 
-    CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER    // Provide StringMaker specialization for std::pair
-    CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER   // Provide StringMaker specialization for std::tuple
-    CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER  // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
-    CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS    // Defines all of the above
+    CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER     // Provide StringMaker specialization for std::pair
+    CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER    // Provide StringMaker specialization for std::tuple
+    CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER   // Provide StringMaker specialization for std::chrono::duration, std::chrono::timepoint
+    CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER  // Provide StringMaker specialization for std::variant, std::monostate (on C++17)
+    CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER // Provide StringMaker specialization for std::optional (on C++17)
+    CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS     // Defines all of the above
 
 
+## Disabling exceptions
+
+By default, Catch2 uses exceptions to signal errors and to abort tests
+when an assertion from the `REQUIRE` family of assertions fails. We also
+provide an experimental support for disabling exceptions. Catch2 should
+automatically detect when it is compiled with exceptions disabled, but
+it can be forced to compile without exceptions by defining
+
+    CATCH_CONFIG_DISABLE_EXCEPTIONS
+
+Note that when using Catch2 without exceptions, there are 2 major
+limitations:
+
+1) If there is an error that would normally be signalled by an exception,
+the exception's message will instead be written to `Catch::cerr` and
+`std::terminate` will be called.
+2) If an assertion from the `REQUIRE` family of macros fails,
+`std::terminate` will be called after the active reporter returns.
+
+
+There is also a customization point for the exact behaviour of what
+happens instead of exception being thrown. To use it, define
+
+    CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER
+
+and provide a definition for this function:
+
+```cpp
+namespace Catch {
+    [[noreturn]]
+    void throw_exception(std::exception const&);
+}
+```
+
 ---
 
 [Home](Readme.md#top)
diff --git a/docs/contributing.md b/docs/contributing.md
index b615037..21bbad1 100644
--- a/docs/contributing.md
+++ b/docs/contributing.md
@@ -1,8 +1,8 @@
 <a id="top"></a>
 # Contributing to Catch
 
-So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for 
-additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated. 
+So you want to contribute something to Catch? That's great! Whether it's a bug fix, a new feature, support for
+additional compilers - or just a fix to the documentation - all contributions are very welcome and very much appreciated.
 Of course so are bug reports and other comments and questions.
 
 If you are contributing to the code base there are a few simple guidelines to keep in mind. This also includes notes to
@@ -16,7 +16,7 @@
 
 ## Directory structure
 
-_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still, 
+_Users_ of Catch primarily use the single header version. _Maintainers_ should work with the full source (which is still,
 primarily, in headers). This can be found in the `include` folder. There are a set of test files, currently under
 `projects/SelfTest`. The test app can be built via CMake from the `CMakeLists.txt` file in the root, or you can generate
 project files for Visual Studio, XCode, and others (instructions in the `projects` folder). If you have access to CLion,
@@ -37,20 +37,42 @@
 
 ## Testing your changes
 
-Obviously all changes to Catch's code should be tested. If you added new functionality, you should add tests covering and
-showcasing it. Even if you have only made changes to Catch internals (ie you implemented some performance improvements),
-you should still test your changes.
+Obviously all changes to Catch's code should be tested. If you added new
+functionality, you should add tests covering and showcasing it. Even if you have
+only made changes to Catch internals (i.e. you implemented some performance
+improvements), you should still test your changes.
 
-This means 3 things
+This means 2 things
 
-* Compiling Catch's SelfTest project -- code that does not compile is evidently incorrect. Obviously, you are not expected to
-have access to all compilers and platforms Catch supports, Catch's CI pipeline will compile your code using supported compilers
-once you open a PR.
-* Running the SelfTest binary. There should be no unexpected failures on simple run.
-* Running Catch's approval tests. Approval tests compare current output of the SelfTest binary in various configurations against
-known good output. Catch's repository provides utility scripts `approvalTests.py` to help you with this. It needs to be passed
-the SelfTest binary compiled with your changes, like so: `$ ./scripts/approvalTests.py clang-build/SelfTest`. The output should
-be fairly self-explanatory.
+* Compiling Catch's SelfTest project:
+```
+$ cd Catch2
+$ cmake -Bdebug-build -H. -DCMAKE_BUILD_TYPE=Debug
+$ cmake --build debug-build
+```
+because code that does not compile is evidently incorrect. Obviously,
+you are not expected to have access to all the compilers and platforms
+supported by Catch2, but you should at least smoke test your changes
+on your platform. Our CI pipeline will check your PR against most of
+the supported platforms, but it takes an hour to finish -- compiling
+locally takes just a few minutes.
+
+
+* Running the tests via CTest:
+```
+$ cd debug-build
+$ ctest -j 2 --output-on-failure
+```
+If you added new tests, approval tests are very likely to fail. If they
+do not, it means that your changes weren't run as part of them. This
+_might_ be intentional, but usually is not.
+
+The approval tests compare current output of the SelfTest binary in various
+configurations against known good outputs. The reason it fails is,
+_usually_, that you've added new tests but have not yet approved the changes
+they introduce. This is done with the `scripts/approve.py` script, but
+before you do so, you need to check that the introduced changes are indeed
+intentional.
 
 
 
diff --git a/docs/deprecations.md b/docs/deprecations.md
new file mode 100644
index 0000000..0489e1f
--- /dev/null
+++ b/docs/deprecations.md
@@ -0,0 +1,93 @@
+<a id="top"></a>
+# Deprecations and incoming changes
+
+This page documents current deprecations and upcoming planned changes
+inside Catch2. The difference between these is that a deprecated feature
+will be removed, while a planned change to a feature means that the
+feature will behave differently, but will still be present. Obviously,
+either of these is a breaking change, and thus will not happen until
+at least the next major release.
+
+
+## Deprecations
+
+### `--list-*` return values
+
+The return codes of the `--list-*` family of command line arguments
+will no longer be equal to the number of tests/tags/etc found, instead
+it will be 0 for success and non-zero for failure.
+
+
+### `--list-test-names-only`
+
+`--list-test-names-only` command line argument will be removed.
+
+
+### `ANON_TEST_CASE`
+
+`ANON_TEST_CASE` is scheduled for removal, as it can be fully replaced
+by a `TEST_CASE` with no arguments.
+
+
+### Secondary description amongst tags
+
+Currently, the tags part of `TEST_CASE` (and others) macro can also
+contain text that is not part of tags. This text is then separated into
+a "description" of the test case, but the description is then never used
+apart from writing it out for `--list-tests -v high`.
+
+Because it isn't actually used nor documented, and brings complications
+to Catch2's internals, description support will be removed.
+
+
+## Planned changes
+
+
+### Reporter verbosities
+
+The current implementation of verbosities, where the reporter is checked
+up-front whether it supports the requested verbosity, is fundamentally
+misguided and will be changed. The new implementation will no longer check
+whether the specified reporter supports the requested verbosity, instead
+it will be up to the reporters to deal with verbosities as they see fit
+(with an expectation that unsupported verbosities will be, at most,
+warnings, but not errors).
+
+
+### Output format of `--list-*` command line parameters
+
+The various list operations will be piped through reporters. This means
+that e.g. XML reporter will write the output as machine-parseable XML,
+while the Console reporter will keep the current, human-oriented output.
+
+
+### `CHECKED_IF` and `CHECKED_ELSE`
+
+To make the `CHECKED_IF` and `CHECKED_ELSE` macros more useful, they will
+be marked as "OK to fail" (`Catch::ResultDisposition::SuppressFail` flag
+will be added), which means that their failure will not fail the test,
+making the `else` actually useful.
+
+
+### Change semantics of `[.]` and tag exclusion
+
+Currently, given these 2 tests
+```cpp
+TEST_CASE("A", "[.][foo]") {}
+TEST_CASE("B", "[.][bar]") {}
+```
+specifying `[foo]` as the testspec will run test "A" and specifying
+`~[foo]` will run test "B", even though it is hidden. Also, specifying
+`~[baz]` will run both tests. This behaviour is often surprising and will
+be changed so that hidden tests are included in a run only if they
+positively match a testspec.
+
+
+### Console Colour API
+
+The API for Catch2's console colour will be changed to take an extra
+argument, the stream to which the colour code should be applied.
+
+---
+
+[Home](Readme.md#top)
diff --git a/docs/event-listeners.md b/docs/event-listeners.md
index 1ddef0f..c6625a2 100644
--- a/docs/event-listeners.md
+++ b/docs/event-listeners.md
@@ -44,7 +44,7 @@
 
 ## Events that can be hooked
 
-The following are the methods that can be overriden in the Listener:
+The following are the methods that can be overridden in the Listener:
 
 ```c++
 // The whole test run, starting and ending
diff --git a/docs/generators.md b/docs/generators.md
new file mode 100644
index 0000000..8ad47e3
--- /dev/null
+++ b/docs/generators.md
@@ -0,0 +1,133 @@
+<a id="top"></a>
+# Data Generators
+
+Data generators (also known as _data driven/parametrized test cases_)
+let you reuse the same set of assertions across different input values.
+In Catch2, this means that they respect the ordering and nesting
+of the `TEST_CASE` and `SECTION` macros, and their nested sections
+are run once per each value in a generator.
+
+This is best explained with an example:
+```cpp
+TEST_CASE("Generators") {
+    auto i = GENERATE(1, 2, 3);
+    SECTION("one") {
+        auto j = GENERATE( -3, -2, -1 );
+        REQUIRE(j < i);
+    }
+}
+```
+
+The assertion in this test case will be run 9 times, because there
+are 3 possible values for `i` (1, 2, and 3) and there are 3 possible
+values for `j` (-3, -2, and -1).
+
+
+There are 2 parts to generators in Catch2, the `GENERATE` macro together
+with the already provided generators, and the `IGenerator<T>` interface
+that allows users to implement their own generators.
+
+## Provided generators
+
+Catch2's provided generator functionality consists of three parts,
+
+* `GENERATE` macro,  that serves to integrate generator expression with
+a test case,
+* 2 fundamental generators
+  * `ValueGenerator<T>` -- contains only single element
+  * `ValuesGenerator<T>` -- contains multiple elements
+* 5 generic generators that modify other generators
+  * `FilterGenerator<T, Predicate>` -- filters out elements from a generator
+  for which the predicate returns "false"
+  * `TakeGenerator<T>` -- takes first `n` elements from a generator
+  * `RepeatGenerator<T>` -- repeats output from a generator `n` times
+  * `MapGenerator<T, U, Func>` -- returns the result of applying `Func`
+  on elements from a different generator
+  * `ChunkGenerator<T>` -- returns chunks (inside `std::vector`) of n elements from a generator
+* 3 specific purpose generators
+  * `RandomIntegerGenerator<Integral>` -- generates random Integrals from range
+  * `RandomFloatGenerator<Float>` -- generates random Floats from range
+  * `RangeGenerator<T>` -- generates all values inside a specific range
+
+The generators also have associated helper functions that infer their
+type, making their usage much nicer. These are
+
+* `value(T&&)` for `ValueGenerator<T>`
+* `values(std::initializer_list<T>)` for `ValuesGenerator<T>`
+* `filter(predicate, GeneratorWrapper<T>&&)` for `FilterGenerator<T, Predicate>`
+* `take(count, GeneratorWrapper<T>&&)` for `TakeGenerator<T>`
+* `repeat(repeats, GeneratorWrapper<T>&&)` for `RepeatGenerator<T>`
+* `map(func, GeneratorWrapper<T>&&)` for `MapGenerator<T, T, Func>` (map `T` to `T`)
+* `map<T>(func, GeneratorWrapper<U>&&)` for `MapGenerator<T, U, Func>` (map `U` to `T`)
+* `chunk(chunk-size, GeneratorWrapper<T>&&)` for `ChunkGenerator<T>`
+* `random(IntegerOrFloat a, IntegerOrFloat b)` for `RandomIntegerGenerator` or `RandomFloatGenerator`
+* `range(start, end)` for `RangeGenerator<T>` with a step size of `1` 
+* `range(start, end, step)` for `RangeGenerator<T>` with a custom step size
+
+
+And can be used as shown in the example below to create a generator
+that returns 100 odd random number:
+
+```cpp
+TEST_CASE("Generating random ints", "[example][generator]") {
+    SECTION("Deducing functions") {
+        auto i = GENERATE(take(100, filter([](int i) { return i % 2 == 1; }, random(-100, 100))));
+        REQUIRE(i > -100);
+        REQUIRE(i < 100);
+        REQUIRE(i % 2 == 1);
+    }
+}
+```
+
+
+Apart from registering generators with Catch2, the `GENERATE` macro has
+one more purpose, and that is to provide simple way of generating trivial
+generators, as seen in the first example on this page, where we used it
+as `auto i = GENERATE(1, 2, 3);`. This usage converted each of the three
+literals into a single `ValueGenerator<int>` and then placed them all in
+a special generator that concatenates other generators. It can also be
+used with other generators as arguments, such as `auto i = GENERATE(0, 2,
+take(100, random(300, 3000)));`. This is useful e.g. if you know that
+specific inputs are problematic and want to test them separately/first.
+
+**For safety reasons, you cannot use variables inside the `GENERATE` macro.**
+
+You can also override the inferred type by using `as<type>` as the first
+argument to the macro. This can be useful when dealing with string literals,
+if you want them to come out as `std::string`:
+
+```cpp
+TEST_CASE("type conversion", "[generators]") {
+    auto str = GENERATE(as<std::string>{}, "a", "bb", "ccc");`
+    REQUIRE(str.size() > 0);
+}
+```
+
+## Generator interface
+
+You can also implement your own generators, by deriving from the
+`IGenerator<T>` interface:
+
+```cpp
+template<typename T>
+struct IGenerator : GeneratorUntypedBase {
+    // via GeneratorUntypedBase:
+    // Attempts to move the generator to the next element.
+    // Returns true if successful (and thus has another element that can be read)
+    virtual bool next() = 0;
+
+    // Precondition:
+    // The generator is either freshly constructed or the last call to next() returned true
+    virtual T const& get() const = 0;
+};
+```
+
+However, to be able to use your custom generator inside `GENERATE`, it
+will need to be wrapped inside a `GeneratorWrapper<T>`.
+`GeneratorWrapper<T>` is a value wrapper around a
+`std::unique_ptr<IGenerator<T>>`.
+
+For full example of implementing your own generator, look into Catch2's
+examples, specifically
+[Generators: Create your own generator](../examples/300-Gen-OwnGenerator.cpp).
+
diff --git a/docs/limitations.md b/docs/limitations.md
index bcdbab0..b95cd87 100644
--- a/docs/limitations.md
+++ b/docs/limitations.md
@@ -1,12 +1,19 @@
 <a id="top"></a>
 # Known limitations
 
-Catch has some known limitations, that we are not planning to change. Some of these are caused by our desire to support C++98 compilers, some of these are caused by our desire to keep Catch crossplatform, some exist because their priority is seen as low compared to the development effort they would need and some other yet are compiler/runtime bugs.
+Over time, some limitations of Catch2 emerged. Some of these are due
+to implementation details that cannot be easily changed, some of these
+are due to lack of development resources on our part, and some of these
+are due to plain old 3rd party bugs.
+
 
 ## Implementation limits
 ### Sections nested in loops
 
-If you are using `SECTION`s inside loops, you have to create them with different name per loop's iteration. The recommended way to do so is to incorporate the loop's counter into section's name, like so
+If you are using `SECTION`s inside loops, you have to create them with
+different name per loop's iteration. The recommended way to do so is to
+incorporate the loop's counter into section's name, like so:
+
 ```cpp
 TEST_CASE( "Looped section" ) {
     for (char i = '0'; i < '5'; ++i) {
@@ -17,11 +24,34 @@
 }
 ```
 
+or with a `DYNAMIC_SECTION` macro (that was made for exactly this purpose):
+
+```cpp
+TEST_CASE( "Looped section" ) {
+    for (char i = '0'; i < '5'; ++i) {
+        DYNAMIC_SECTION( "Looped section " << i) {
+            SUCCEED( "Everything is OK" );
+        }
+    }
+}
+```
+
+### Tests might be run again if last section fails
+
+If the last section in a test fails, it might be run again. This is because
+Catch2 discovers `SECTION`s dynamically, as they are about to run, and
+if the last section in test case is aborted during execution (e.g. via
+the `REQUIRE` family of macros), Catch2 does not know that there are no
+more sections in that test case and must run the test case again.
+
+
 ## Features
 This section outlines some missing features, what is their status and their possible workarounds.
 
 ### Thread safe assertions
-Because threading support in standard C++98 is limited (well, non-existent), assertion macros in Catch are not thread safe. This does not mean that you cannot use threads inside Catch's test, but that only single thread can interact with Catch's assertions and other macros.
+Catch2's assertion macros are not thread safe. This does not mean that
+you cannot use threads inside Catch's test, but that only single thread
+can interact with Catch's assertions and other macros.
 
 This means that this is ok
 ```cpp
@@ -49,8 +79,8 @@
     REQUIRE(cnt == 16);
 ```
 
-
-_This limitation is highly unlikely to be lifted before Catch 2 is released._
+Because C++11 provides the necessary tools to do this, we are planning
+to remove this limitation in the future.
 
 ### Process isolation in a test
 Catch does not support running tests in isolated (forked) processes. While this might in the future, the fact that Windows does not support forking and only allows full-on process creation and the desire to keep code as similar as possible across platforms, mean that this is likely to take significant development time, that is not currently available.
@@ -96,6 +126,14 @@
   ""\" == ""\"
 ```
 
+### Visual Studio 2015 -- Alignment compilation error (C2718)
+
+VS 2015 has a known bug, where `declval<T>` can cause compilation error
+if `T` has alignment requirements that it cannot meet.
+
+
+A workaround is to explicitly specialize `Catch::is_range` for given
+type (this avoids code path that uses `declval<T>` in a SFINAE context).
 
 
 ### Visual Studio 2015 -- Wrong line number reported in debug mode
@@ -127,3 +165,14 @@
 This is a bug in `libstdc++-4.8`, where all matching methods from `<regex>` return false. Since `Matches` uses `<regex>` internally, if the underlying implementation does not work, it doesn't work either.
 
 Workaround: Use newer version of `libstdc++`.
+
+
+### libstdc++, `_GLIBCXX_DEBUG` macro and random ordering of tests
+
+Running a Catch2 binary compiled against libstdc++ with `_GLIBCXX_DEBUG`
+macro defined with `--order rand` will cause a debug check to trigger and
+abort the run due to self-assignment.
+[This is a known bug inside libstdc++](https://stackoverflow.com/questions/22915325/avoiding-self-assignment-in-stdshuffle/23691322)
+
+Workaround: Don't use `--order rand` when compiling against debug-enabled
+libstdc++.
diff --git a/docs/list-of-examples.md b/docs/list-of-examples.md
index 6517d5d..677dec1 100644
--- a/docs/list-of-examples.md
+++ b/docs/list-of-examples.md
@@ -1,18 +1,32 @@
 <a id="top"></a>
 # List of examples
 
+## Already available
+
+- Catch main: [Catch-provided main](../examples/000-CatchMain.cpp)
 - Test Case: [Single-file](../examples/010-TestCase.cpp)
-- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-1.cpp)
+- Test Case: [Multiple-file 1](../examples/020-TestCase-1.cpp), [2](../examples/020-TestCase-2.cpp)
 - Assertion: [REQUIRE, CHECK](../examples/030-Asn-Require-Check.cpp)
+- Fixture: [Sections](../examples/100-Fix-Section.cpp)
+- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
+- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
+- Report: [Catch-provided main](../examples/200-Rpt-CatchMain.cpp)
+- Report: [TeamCity reporter](../examples/207-Rpt-TeamCityReporter.cpp)
+- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
+- Configuration: [Provide your own output streams](../examples/231-Cfg-OutputStreams.cpp)
+- Generators: [Create your own generator](../examples/300-Gen-OwnGenerator.cpp)
+- Generators: [Use map to convert types in GENERATE expression](../examples/301-Gen-MapTypeConversion.cpp)
+- Generators: [Use variables in generator expressions](../examples/310-Gen-VariablesInGenerators.cpp)
+
+
+## Planned
+
 - Assertion: [REQUIRE_THAT and Matchers](../examples/040-Asn-RequireThat.cpp)
 - Assertion: [REQUIRE_NO_THROW](../examples/050-Asn-RequireNoThrow.cpp)
 - Assertion: [REQUIRE_THROWS](../examples/050-Asn-RequireThrows.cpp)
 - Assertion: [REQUIRE_THROWS_AS](../examples/070-Asn-RequireThrowsAs.cpp)
 - Assertion: [REQUIRE_THROWS_WITH](../examples/080-Asn-RequireThrowsWith.cpp)
 - Assertion: [REQUIRE_THROWS_MATCHES](../examples/090-Asn-RequireThrowsMatches.cpp)
-- Fixture: [Sections](../examples/100-Fix-Section.cpp)
-- Fixture: [Class-based fixtures](../examples/110-Fix-ClassFixture.cpp)
-- BDD: [SCENARIO, GIVEN, WHEN, THEN](../examples/120-Bdd-ScenarioGivenWhenThen.cpp)
 - Floating point: [Approx - Comparisons](../examples/130-Fpt-Approx.cpp)
 - Logging: [CAPTURE - Capture expression](../examples/140-Log-Capture.cpp)
 - Logging: [INFO - Provide information with failure](../examples/150-Log-Info.cpp)
@@ -20,8 +34,10 @@
 - Logging: [FAIL, FAIL_CHECK - Issue message and force failure/continue](../examples/170-Log-Fail.cpp)
 - Logging: [SUCCEED - Issue message and continue](../examples/180-Log-Succeed.cpp)
 - Report: [User-defined type](../examples/190-Rpt-ReportUserDefinedType.cpp)
-- Report: [Reporter](../examples/200-Rpt-UserDefinedReporter.cpp)
-- Listener: [Listeners](../examples/210-Evt-EventListeners.cpp)
+- Report: [User-defined reporter](../examples/202-Rpt-UserDefinedReporter.cpp)
+- Report: [Automake reporter](../examples/205-Rpt-AutomakeReporter.cpp)
+- Report: [TAP reporter](../examples/206-Rpt-TapReporter.cpp)
+- Report: [Multiple reporter](../examples/208-Rpt-MultipleReporters.cpp)
 - Configuration: [Provide your own main()](../examples/220-Cfg-OwnMain.cpp)
 - Configuration: [Compile-time configuration](../examples/230-Cfg-CompileTimeConfiguration.cpp)
 - Configuration: [Run-time configuration](../examples/240-Cfg-RunTimeConfiguration.cpp)
diff --git a/docs/logging.md b/docs/logging.md
index 7ae54aa..e896a57 100644
--- a/docs/logging.md
+++ b/docs/logging.md
@@ -1,7 +1,7 @@
 <a id="top"></a>
 # Logging macros
 
-Additional messages can be logged during a test case. Note that the messages are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
+Additional messages can be logged during a test case. Note that the messages logged with `INFO` are scoped and thus will not be reported if failure occurs in scope preceding the message declaration. An example:
 
 ```cpp
 TEST_CASE("Foo") {
@@ -28,6 +28,60 @@
 ```
 When the last `CHECK` fails in the "Bar" test case, then only one message will be printed: `Test case start`.
 
+## Logging without local scope
+
+`UNSCOPED_INFO` is similar to `INFO` with two key differences:
+
+- Lifetime of an unscoped message is not tied to its own scope.
+- An unscoped message can be reported by the first following assertion only, regardless of the result of that assertion.
+
+In other words, lifetime of `UNSCOPED_INFO` is limited by the following assertion (or by the end of test case/section, whichever comes first) whereas lifetime of `INFO` is limited by its own scope.
+
+These differences make this macro useful for reporting information from helper functions or inner scopes. An example:
+
+```cpp
+void print_some_info() {
+    UNSCOPED_INFO("Info from helper");
+}
+
+TEST_CASE("Baz") {
+    print_some_info();
+    for (int i = 0; i < 2; ++i) {
+        UNSCOPED_INFO("The number is " << i);
+    }
+    CHECK(false);
+}
+
+TEST_CASE("Qux") {
+    INFO("First info");
+    UNSCOPED_INFO("First unscoped info");
+    CHECK(false);
+
+    INFO("Second info");
+    UNSCOPED_INFO("Second unscoped info");
+    CHECK(false);
+}
+```
+
+"Baz" test case prints:
+```
+Info from helper
+The number is 0
+The number is 1
+```
+
+With "Qux" test case, two messages will be printed when the first `CHECK` fails:
+```
+First info
+First unscoped info
+```
+
+"First unscoped info" message will be cleared after the first `CHECK`, while "First info" message will persist until the end of the test case. Therefore, when the second `CHECK` fails, three messages will be printed:
+```
+First info
+Second info
+Second unscoped info
+```
 
 ## Streaming macros
 
@@ -43,7 +97,14 @@
 
 **INFO(** _message expression_ **)**
 
-The message is logged to a buffer, but only reported with the next assertion that is logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
+The message is logged to a buffer, but only reported with next assertions that are logged. This allows you to log contextual information in case of failures which is not shown during a successful test run (for the console reporter, without -s). Messages are removed from the buffer at the end of their scope, so may be used, for example, in loops.
+
+_Note that in Catch2 2.x.x `INFO` can be used without a trailing semicolon as there is a trailing semicolon inside macro.
+This semicolon will be removed with next major version. It is highly advised to use a trailing semicolon after `INFO` macro._
+
+**UNSCOPED_INFO(** _message expression_ **)**
+
+Similar to `INFO`, but messages are not limited to their own scope: They are removed from the buffer after each assertion, section or test case, whichever comes first.
 
 **WARN(** _message expression_ **)**
 
@@ -57,26 +118,37 @@
 
 AS `FAIL`, but does not abort the test
 
-## Quickly capture a variable value
+## Quickly capture value of variables or expressions
 
-**CAPTURE(** _expression_ **)**
+**CAPTURE(** _expression1_, _expression2_, ... **)**
 
-Sometimes you just want to log the name and value of a variable. While you can easily do this with the INFO macro, above, as a convenience the CAPTURE macro handles the stringising of the variable name for you (actually it works with any expression, not just variables).
+Sometimes you just want to log a value of variable, or expression. For
+convenience, we provide the `CAPTURE` macro, that can take a variable,
+or an expression, and prints out that variable/expression and its value
+at the time of capture.
 
-E.g.
-```c++
-CAPTURE( theAnswer );
+e.g. `CAPTURE( theAnswer );` will log message "theAnswer := 42", while
+```cpp
+int a = 1, b = 2, c = 3;
+CAPTURE( a, b, c, a + b, c > b, a == 1);
+```
+will log a total of 6 messages:
+```
+a := 1
+b := 2
+c := 3
+a + b := 3
+c > b := true
+a == 1 := true
 ```
 
-This would log something like:
+You can also capture expressions that use commas inside parentheses
+(e.g. function calls), brackets, or braces (e.g. initializers). To
+properly capture expression that contains template parameters list
+(in other words, it contains commas between angle brackets), you need
+to enclose the expression inside parentheses:
+`CAPTURE( (std::pair<int, int>{1, 2}) );`
 
-<pre>"theAnswer := 42"</pre>
-
-## Deprecated macros
-
-**SCOPED_INFO and SCOPED_CAPTURE**
-
-These macros are now deprecated and are just aliases for INFO and CAPTURE (which were not previously scoped).
 
 ---
 
diff --git a/docs/matchers.md b/docs/matchers.md
index fb95ce2..adbd4ce 100644
--- a/docs/matchers.md
+++ b/docs/matchers.md
@@ -53,6 +53,25 @@
 Do note that ULP-based checks only make sense when both compared numbers are of the same type and `WithinULP` will use type of its argument as the target type. This means that `WithinULP(1.f, 1)` will expect to compare `float`s, but `WithinULP(1., 1)` will expect to compare `double`s.
 
 
+### Generic matchers
+Catch also aims to provide a set of generic matchers. Currently this set
+contains only a matcher that takes arbitrary callable predicate and applies
+it onto the provided object.
+
+Because of type inference limitations, the argument type of the predicate
+has to be provided explicitly. Example:
+```cpp
+REQUIRE_THAT("Hello olleH",
+             Predicate<std::string>(
+                 [] (std::string const& str) -> bool { return str.front() == str.back(); },
+                 "First and last character should be equal")
+);
+```
+
+The second argument is an optional description of the predicate, and is
+used only during reporting of the result.
+
+
 ## Custom matchers
 It's easy to provide your own matchers to extend Catch or just to work with your own types.
 
diff --git a/docs/opensource-users.md b/docs/opensource-users.md
index 43596cc..d71b425 100644
--- a/docs/opensource-users.md
+++ b/docs/opensource-users.md
@@ -1,42 +1,45 @@
 <a id="top"></a>
 # Open Source projects using Catch
 
-Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution 
+Catch is great for open source. With its [liberal license](../LICENSE.txt) and single-header, dependency-free, distribution
 it's easy to just drop the header into your project and start writing tests - what's not to like?
 
 As a result Catch is now being used in many Open Source projects, including some quite well known ones.
 This page is an attempt to track those projects. Obviously it can never be complete.
 This effort largely relies on the maintainers of the projects themselves updating this page and submitting a PR
-(or, if you prefer contact one of the maintainers of Catch directly, use the 
+(or, if you prefer contact one of the maintainers of Catch directly, use the
 [forums](https://groups.google.com/forum/?fromgroups#!forum/catch-forum)), or raise an [issue](https://github.com/philsquared/Catch/issues) to let us know).
 Of course users of those projects might want to update this page too. That's fine - as long you're confident the project maintainers won't mind.
-If you're an Open Source project maintainer and see your project listed here but would rather it wasn't - 
+If you're an Open Source project maintainer and see your project listed here but would rather it wasn't -
 just let us know via any of the previously mentioned means - although I'm sure there won't be many who feel that way.
- 
+
 Listing a project here does not imply endorsement and the plan is to keep these ordered alphabetically to avoid an implication of relative importance.
 
 ## Libraries & Frameworks
 
 ### [Azmq](https://github.com/zeromq/azmq)
-Boost Asio style bindings for ZeroMQ
+Boost Asio style bindings for ZeroMQ.
 
 ### [ChakraCore](https://github.com/Microsoft/ChakraCore)
-The core part of the Chakra Javascript engine that powers Microsoft Edge
+The core part of the Chakra JavaScript engine that powers Microsoft Edge.
 
 ### [ChaiScript](https://github.com/ChaiScript/ChaiScript)
-A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques
+A, header-only, embedded scripting language designed from the ground up to directly target C++ and take advantage of modern C++ development techniques.
 
 ### [Clara](https://github.com/philsquared/Clara)
 A, single-header-only, type-safe, command line parser - which also prints formatted usage strings.
 
 ### [Couchbase-lite-core](https://github.com/couchbase/couchbase-lite-core)
-The next-generation core storage and query engine for Couchbase Lite
+The next-generation core storage and query engine for Couchbase Lite.
+
+### [cppcodec](https://github.com/tplgy/cppcodec)
+Header-only C++11 library to encode/decode base64, base64url, base32, base32hex and hex (a.k.a. base16) as specified in RFC 4648, plus Crockford's base32.
 
 ### [DtCraft](https://github.com/twhuang-uiuc/DtCraft)
-A High-performance Cluster Computing Engine
+A High-performance Cluster Computing Engine.
 
 ### [forest](https://github.com/xorz57/forest)
-Forest is an open-source, template library of tree data structures written in C++11.
+Template Library of Tree Data Structures.
 
 ### [Fuxedo](https://github.com/fuxedo/fuxedo)
 Open source Oracle Tuxedo-like XATMI middleware for C and C++.
@@ -47,6 +50,9 @@
 ### [JSON for Modern C++](https://github.com/nlohmann/json)
 A, single-header, JSON parsing library that takes advantage of what C++ has to offer.
 
+### [libcluon](https://github.com/chrberger/libcluon)
+A single-header-only library written in C++14 to glue distributed software components (UDP, TCP, shared memory) supporting natively Protobuf, LCM/ZCM, MsgPack, and JSON for dynamic message transformations in-between. 
+
 ### [MNMLSTC Core](https://github.com/mnmlstc/core)
 A small and easy to use C++11 library that adds a functionality set that will be available in C++14 and later, as well as some useful additions.
 
@@ -57,22 +63,25 @@
 A header-only framework for benchmarking small snippets of C++ code.
 
 ### [SOCI](https://github.com/SOCI/soci)
-The C++ Database Access Library
+The C++ Database Access Library.
 
 ### [polymorphic_value](https://github.com/jbcoe/polymorphic_value)
-A polymorphic value-type for C++
+A polymorphic value-type for C++.
 
 ### [Ppconsul](https://github.com/oliora/ppconsul)
-A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure
+A C++ client library for Consul. Consul is a distributed tool for discovering and configuring services in your infrastructure.
 
 ### [Reactive-Extensions/ RxCpp](https://github.com/Reactive-Extensions/RxCpp)
-A library of algorithms for values-distributed-in-time
+A library of algorithms for values-distributed-in-time.
+
+### [thor](https://github.com/xorz57/thor)
+Wrapper Library for CUDA.
 
 ### [TextFlowCpp](https://github.com/philsquared/textflowcpp)
-A small, single-header-only, library for wrapping and composing columns of text
+A small, single-header-only, library for wrapping and composing columns of text.
 
 ### [Trompeloeil](https://github.com/rollbear/trompeloeil)
-A thread safe header only mocking framework for C++14
+A thread-safe header-only mocking framework for C++14.
 
 ### [args](https://github.com/Taywee/args)
 A simple header-only C++ argument parser library.
@@ -86,13 +95,16 @@
 Minimal, open-source and cross-platform audio tool for live music production.
 
 ### [MAME](https://github.com/mamedev/mame)
-MAME originally stood for Multiple Arcade Machine Emulator
+MAME originally stood for Multiple Arcade Machine Emulator.
 
 ### [Newsbeuter](https://github.com/akrennmair/newsbeuter)
 Newsbeuter is an open-source RSS/Atom feed reader for text terminals.
 
+### [SpECTRE](https://github.com/sxs-collaboration/spectre)
+SpECTRE is a code for multi-scale, multi-physics problems in astrophysics and gravitational physics.
+
 ### [Standardese](https://github.com/foonathan/standardese)
-Standardese aims to be a nextgen Doxygen
+Standardese aims to be a nextgen Doxygen.
 
 ---
 
diff --git a/docs/other-macros.md b/docs/other-macros.md
new file mode 100644
index 0000000..6f5fac7
--- /dev/null
+++ b/docs/other-macros.md
@@ -0,0 +1,150 @@
+<a id="top"></a>
+# Other macros
+
+This page serves as a reference for macros that are not documented
+elsewhere. For now, these macros are separated into 2 rough categories,
+"assertion related macros" and "test case related macros".
+
+## Assertion related macros
+
+* `CHECKED_IF` and `CHECKED_ELSE`
+
+`CHECKED_IF( expr )` is an `if` replacement, that also applies Catch2's
+stringification machinery to the _expr_ and records the result. As with
+`if`, the block after a `CHECKED_IF` is entered only if the expression
+evaluates to `true`. `CHECKED_ELSE( expr )` work similarly, but the block
+is entered only if the _expr_ evaluated to `false`.
+
+Example:
+```cpp
+int a = ...;
+int b = ...;
+CHECKED_IF( a == b ) {
+    // This block is entered when a == b
+} CHECKED_ELSE ( a == b ) {
+    // This block is entered when a != b
+}
+```
+
+* `CHECK_NOFAIL`
+
+`CHECK_NOFAIL( expr )` is a variant of `CHECK` that does not fail the test
+case if _expr_ evaluates to `false`. This can be useful for checking some
+assumption, that might be violated without the test neccessarily failing.
+
+Example output:
+```
+main.cpp:6:
+FAILED - but was ok:
+  CHECK_NOFAIL( 1 == 2 )
+
+main.cpp:7:
+PASSED:
+  CHECK( 2 == 2 )
+```
+
+* `SUCCEED`
+
+`SUCCEED( msg )` is mostly equivalent with `INFO( msg ); REQUIRE( true );`.
+In other words, `SUCCEED` is for cases where just reaching a certain line
+means that the test has been a success.
+
+Example usage:
+```cpp
+TEST_CASE( "SUCCEED showcase" ) {
+    int I = 1;
+    SUCCEED( "I is " << I );
+}
+```
+
+* `STATIC_REQUIRE`
+
+`STATIC_REQUIRE( expr )` is a macro that can be used the same way as a
+`static_assert`, but also registers the success with Catch2, so it is
+reported as a success at runtime. The whole check can also be deferred
+to the runtime, by defining `CATCH_CONFIG_RUNTIME_STATIC_REQUIRE` before
+including the Catch2 header.
+
+Example:
+```cpp
+TEST_CASE("STATIC_REQUIRE showcase", "[traits]") {
+    STATIC_REQUIRE( std::is_void<void>::value );
+    STATIC_REQUIRE_FALSE( std::is_void<int>::value );
+}
+```
+
+## Test case related macros
+
+* `METHOD_AS_TEST_CASE`
+
+`METHOD_AS_TEST_CASE( member-function-pointer, description )` lets you
+register a member function of a class as a Catch2 test case. The class
+will be separately instantiated for each method registered in this way.
+
+```cpp
+class TestClass {
+    std::string s;
+
+public:
+    TestClass()
+        :s( "hello" )
+    {}
+
+    void testCase() {
+        REQUIRE( s == "hello" );
+    }
+};
+
+
+METHOD_AS_TEST_CASE( TestClass::testCase, "Use class's method as a test case", "[class]" )
+```
+
+* `REGISTER_TEST_CASE`
+
+`REGISTER_TEST_CASE( function, description )` let's you register
+a `function` as a test case. The function has to have `void()` signature,
+the description can contain both name and tags.
+
+Example:
+```cpp
+REGISTER_TEST_CASE( someFunction, "ManuallyRegistered", "[tags]" );
+```
+
+_Note that the registration still has to happen before Catch2's session
+is initiated. This means that it either needs to be done in a global
+constructor, or before Catch2's session is created in user's own main._
+
+
+* `ANON_TEST_CASE`
+
+`ANON_TEST_CASE` is a `TEST_CASE` replacement that will autogenerate
+unique name. The advantage of this is that you do not have to think
+of a name for the test case,`the disadvantage is that the name doesn't
+neccessarily remain stable across different links, and thus it might be
+hard to run directly.
+
+Example:
+```cpp
+ANON_TEST_CASE() {
+    SUCCEED("Hello from anonymous test case");
+}
+```
+
+* `DYNAMIC_SECTION`
+
+`DYNAMIC_SECTION` is a `SECTION` where the user can use `operator<<` to
+create the final name for that section. This can be useful with e.g.
+generators, or when creating a `SECTION` dynamically, within a loop.
+
+Example:
+```cpp
+TEST_CASE( "looped SECTION tests" ) {
+    int a = 1;
+
+    for( int b = 0; b < 10; ++b ) {
+        DYNAMIC_SECTION( "b is currently: " << b ) {
+            CHECK( b > a );
+        }
+    }
+}
+```
diff --git a/docs/own-main.md b/docs/own-main.md
index 18d1b7d..6a9b1aa 100644
--- a/docs/own-main.md
+++ b/docs/own-main.md
@@ -1,6 +1,12 @@
 <a id="top"></a>
 # Supplying main() yourself
 
+**Contents**<br>
+[Let Catch take full control of args and config](#let-catch-take-full-control-of-args-and-config)<br>
+[Amending the config](#amending-the-config)<br>
+[Adding your own command line options](#adding-your-own-command-line-options)<br>
+[Version detection](#version-detection)<br>
+
 The easiest way to use Catch is to let it supply ```main()``` for you and handle configuring itself from the command line.
 
 This is achieved by writing ```#define CATCH_CONFIG_MAIN``` before the ```#include "catch.hpp"``` in *exactly one* source file.
@@ -30,7 +36,7 @@
 
 ## Amending the config
 
-If you still want Catch to process the command line, but you want to programatically tweak the config, you can do so in one of two ways:
+If you still want Catch to process the command line, but you want to programmatically tweak the config, you can do so in one of two ways:
 
 ```c++
 #define CATCH_CONFIG_RUNNER
@@ -45,7 +51,7 @@
     
   int returnCode = session.applyCommandLine( argc, argv );
   if( returnCode != 0 ) // Indicates a command line error
-  	  return returnCode;
+        return returnCode;
  
   // writing to session.configData() or session.Config() here 
   // overrides command line args
@@ -94,7 +100,7 @@
   // Let Catch (using Clara) parse the command line
   int returnCode = session.applyCommandLine( argc, argv );
   if( returnCode != 0 ) // Indicates a command line error
-  	return returnCode;
+      return returnCode;
 
   // if set on the command line then 'height' is now set at this point
   if( height > 0 )
diff --git a/docs/release-notes.md b/docs/release-notes.md
index 565d6cd..34278c3 100644
--- a/docs/release-notes.md
+++ b/docs/release-notes.md
@@ -1,20 +1,360 @@
 <a id="top"></a>
 
-# 2.1.1
+# Release notes
+**Contents**<br>
+[2.7.0](#270)<br>
+[2.6.1](#261)<br>
+[2.6.0](#260)<br>
+[2.5.0](#250)<br>
+[2.4.2](#242)<br>
+[2.4.1](#241)<br>
+[2.4.0](#240)<br>
+[2.3.0](#230)<br>
+[2.2.3](#223)<br>
+[2.2.2](#222)<br>
+[2.2.1](#221)<br>
+[2.2.0](#220)<br>
+[2.1.2](#212)<br>
+[2.1.1](#211)<br>
+[2.1.0](#210)<br>
+[2.0.1](#201)<br>
+[Older versions](#older-versions)<br>
+[Even Older versions](#even-older-versions)<br>
 
-## Improvements
+## 2.7.0
+
+### Improvements
+* `TEMPLATE_PRODUCT_TEST_CASE` now uses the resulting type in the name, instead of the serial number (#1544)
+* Catch2's single header is now strictly ASCII (#1542)
+* Added generator for random integral/floating point types
+  * The types are inferred within the `random` helper
+* Added back RangeGenerator (#1526)
+  * RangeGenerator returns elements within a certain range
+* Added ChunkGenerator generic transform (#1538)
+  * A ChunkGenerator returns the elements from different generator in chunks of n elements
+* Added `UNSCOPED_INFO` (#415, #983, #1522)
+  * This is a variant of `INFO` that lives until next assertion/end of the test case.
+
+
+### Fixes
+* All calls to C stdlib functions are now `std::` qualified (#1541)
+  * Code brought in from Clara was also updated.
+* Running tests will no longer open the specified output file twice (#1545)
+  * This would cause trouble when the file was not a file, but rather a named pipe
+  * Fixes the CLion/Resharper integration with Catch
+* Fixed `-Wunreachable-code` occuring with (old) ccache+cmake+clang combination (#1540)
+* Fixed `-Wdefaulted-function-deleted` warning with Clang 8 (#1537)
+* Catch2's type traits and helpers are now properly namespaced inside `Catch::` (#1548)
+* Fixed std{out,err} redirection for failing test (#1514, #1525)
+  * Somehow, this bug has been present for well over a year before it was reported
+
+
+### Contrib
+* `ParseAndAddCatchTests` now properly escapes commas in the test name
+
+
+
+## 2.6.1
+
+### Improvements
+* The JUnit reporter now also reports random seed (#1520, #1521)
+
+### Fixes
+* The TAP reporter now formats comments with test name properly (#1529)
+* `CATCH_REQUIRE_THROWS`'s internals were unified with `REQUIRE_THROWS` (#1536)
+  * This fixes a potential `-Wunused-value` warning when used
+* Fixed a potential segfault when using any of the `--list-*` options (#1533, #1534)
+
+
+## 2.6.0
+
+**With this release the data generator feature is now fully supported.**
+
+
+### Improvements
+* Added `TEMPLATE_PRODUCT_TEST_CASE` (#1454, #1468)
+  * This allows you to easily test various type combinations, see documentation for details
+* The error message for `&&` and `||` inside assertions has been improved (#1273, #1480)
+* The error message for chained comparisons inside assertions has been improved (#1481)
+* Added `StringMaker` specialization for `std::optional` (#1510)
+* The generator interface has been redone once again (#1516)
+  * It is no longer considered experimental and is fully supported
+  * The new interface supports "Input" generators
+  * The generator documentation has been fully updated
+  * We also added 2 generator examples
+
+
+### Fixes
+* Fixed `-Wredundant-move` on newer Clang (#1474)
+* Removed unreachable mentions `std::current_exception`, `std::rethrow_exception` in no-exceptions mode (#1462)
+  * This should fix compilation with IAR
+* Fixed missing `<type_traits>` include (#1494)
+* Fixed various static analysis warnings
+  * Unrestored stream state in `XmlWriter` (#1489)
+  * Potential division by zero in `estimateClockResolution` (#1490)
+  * Uninitialized member in `RunContext` (#1491)
+  * `SourceLineInfo` move ops are now marked `noexcept`
+  * `CATCH_BREAK_INTO_DEBUGGER` is now always a function
+* Fix double run of a test case if user asks for a specific section (#1394, #1492)
+* ANSI colour code output now respects `-o` flag and writes to the file as well (#1502)
+* Fixed detection of `std::variant` support for compilers other than Clang (#1511)
+
+
+### Contrib
+* `ParseAndAddCatchTests` has learned how to use `DISABLED` CTest property (#1452)
+* `ParseAndAddCatchTests` now works when there is a whitspace before the test name (#1493)
+
+
+### Miscellaneous
+* We added new issue templates for reporting issues on GitHub
+* `contributing.md` has been updated to reflect the current test status (#1484)
+
+
+
+## 2.5.0
+
+### Improvements
+* Added support for templated tests via `TEMPLATE_TEST_CASE` (#1437)
+
+
+### Fixes
+* Fixed compilation of `PredicateMatcher<const char*>` by removing partial specialization of `MatcherMethod<T*>`
+* Listeners now implicitly support any verbosity (#1426)
+* Fixed compilation with Embarcadero builder by introducing `Catch::isnan` polyfill (#1438)
+* Fixed `CAPTURE` asserting for non-trivial captures (#1436, #1448)
+
+
+### Miscellaneous
+* We should now be providing first party Conan support via https://bintray.com/catchorg/Catch2 (#1443)
+* Added new section "deprecations and planned changes" to the documentation
+  * It contains summary of what is deprecated and might change with next major version
+* From this release forward, the released headers should be pgp signed (#430)
+  * KeyID `E29C 46F3 B8A7 5028 6079 3B7D ECC9 C20E 314B 2360`
+  * or https://codingnest.com/files/horenmar-publickey.asc
+
+
+## 2.4.2
+
+### Improvements
+* XmlReporter now also outputs the RNG seed that was used in a run (#1404)
+* `Catch::Session::applyCommandLine` now also accepts `wchar_t` arguments.
+  * However, Catch2 still does not support unicode.
+* Added `STATIC_REQUIRE` macro (#1356, #1362)
+* Catch2's singleton's are now cleaned up even if tests are run (#1411)
+  * This is mostly useful as a FP prevention for users who define their own main.
+* Specifying an invalid reporter via `-r` is now reported sooner (#1351, #1422)
+
+
+### Fixes
+* Stringification no longer assumes that `char` is signed (#1399, #1407)
+  * This caused a `Wtautological-compare` warning.
+* SFINAE for `operator<<` no longer sees different overload set than the actual insertion (#1403)
+
+
+### Contrib
+* `catch_discover_tests` correctly adds tests with comma in name (#1327, #1409)
+* Added a new customization point in how the tests are launched to `catch_discover_tests`
+
+
+## 2.4.1
+
+### Improvements
+* Added a StringMaker for `std::(w)string_view` (#1375, #1376)
+* Added a StringMaker for `std::variant` (#1380)
+  * This one is disabled by default to avoid increased compile-time drag
+* Added detection for cygwin environment without `std::to_string` (#1396, #1397)
+
+### Fixes
+* `UnorderedEqualsMatcher` will no longer accept erroneously accept
+vectors that share suffix, but are not permutation of the desired vector
+* Abort after (`-x N`) can no longer be overshot by nested `REQUIRES` and
+subsequently ignored (#1391, #1392)
+
+
+## 2.4.0
+
+**This release brings two new experimental features, generator support
+and a `-fno-exceptions` support. Being experimental means that they
+will not be subject to the usual stability guarantees provided by semver.**
+
+### Improvements
+* Various small runtime performance improvements
+* `CAPTURE` macro is now variadic
+* Added `AND_GIVEN` macro (#1360)
+* Added experimental support for data generators
+  * See [their documentation](generators.md) for details
+* Added support for compiling and running Catch without exceptions
+  * Doing so limits the functionality somewhat
+  * Look [into the documentation](configuration.md#disablingexceptions) for details
+
+### Fixes
+* Suppressed `-Wnon-virtual-dtor` warnings in Matchers (#1357)
+* Suppressed `-Wunreachable-code` warnings in floating point matchers (#1350)
+
+### CMake
+* It is now possible to override which Python is used to run Catch's tests (#1365)
+* Catch now provides infrastructure for adding tests that check compile-time configuration
+* Catch no longer tries to install itself when used as a subproject (#1373)
+* Catch2ConfigVersion.cmake is now generated as arch-independent (#1368)
+  * This means that installing Catch from 32-bit machine and copying it to 64-bit one works
+  * This fixes conan installation of Catch
+
+
+## 2.3.0
+
+**This release changes the include paths provided by our CMake and
+pkg-config integration. The proper include path for the single-header
+when using one of the above is now `<catch2/catch.hpp>`. This change
+also necessitated changes to paths inside the repository, so that the
+single-header version is now at `single_include/catch2/catch.hpp`, rather
+than `single_include/catch.hpp`.**
+
+
+
+### Fixes
+* Fixed Objective-C++ build
+* `-Wunused-variable` suppression no longer leaks from Catch's header under Clang
+* Implementation of the experimental new output capture can now be disabled (#1335)
+  * This allows building Catch2 on platforms that do not provide things like `dup` or `tmpfile`.
+* The JUnit and XML reporters will no longer skip over successful tests when running without `-s`  (#1264, #1267, #1310)
+  * See improvements for more details
+
+### Improvements
+* pkg-config and CMake integration has been rewritten
+  * If you use them, the new include path is `#include <catch2/catch.hpp>`
+  * CMake installation now also installs scripts from `contrib/`
+  * For details see the [new documentation](cmake-integration.md#top)
+* Reporters now have a new customization point, `ReporterPreferences::shouldReportAllAssertions`
+  * When this is set to `false` and the tests are run without `-s`, passing assertions are not sent to the reporter.
+  * Defaults to `false`.
+* Added `DYNAMIC_SECTION`, a section variant that constructs its name using stream
+  * This means that you can do `DYNAMIC_SECTION("For X := " << x)`.
+
+
+## 2.2.3
+
+**To fix some of the bugs, some behavior had to change in potentially breaking manner.**
+**This means that even though this is a patch release, it might not be a drop-in replacement.**
+
+### Fixes
+* Listeners are now called before reporter
+  * This was always documented to be the case, now it actually works that way
+* Catch's commandline will no longer accept multiple reporters
+  * This was done because multiple reporters never worked properly and broke things in non-obvious ways
+  * **This has potential to be a breaking change**
+* MinGW is now detected as Windows platform w/o SEH support (#1257)
+  * This means that Catch2 no longer tries to use POSIX signal handling when compiled with MinGW
+* Fixed potential UB in parsing tags using non-ASCII characters (#1266)
+  * Note that Catch2 still supports only ASCII test names/tags/etc
+* `TEST_CASE_METHOD` can now be used on classnames containing commas (#1245)
+  * You have to enclose the classname in extra set of parentheses
+* Fixed insufficient alt stack size for POSIX signal handling (#1225)
+* Fixed compilation error on Android due to missing `std::to_string` in C++11 mode (#1280)
+* Fixed the order of user-provided `FALLBACK_STRINGIFIER` in stringification machinery (#1024)
+  * It was intended to be replacement for built-in fallbacks, but it was used _after_ them.
+  * **This has potential to be a breaking change**
+* Fixed compilation error when a type has an `operator<<` with templated lhs (#1285, #1306)
+
+### Improvements
+* Added a new, experimental, output capture (#1243)
+  * This capture can also redirect output written via C apis, e.g. `printf`
+  * To opt-in, define `CATCH_CONFIG_EXPERIMENTAL_REDIRECT` in the implementation file
+* Added a new fallback stringifier for classes derived from `std::exception`
+  * Both `StringMaker` specialization and `operator<<` overload are given priority
+
+### Miscellaneous
+* `contrib/` now contains dbg scripts that skip over Catch's internals (#904, #1283)
+  * `gdbinit` for gdb `lldbinit` for lldb
+* `CatchAddTests.cmake` no longer strips whitespace from tests (#1265, #1281)
+* Online documentation now describes `--use-colour` option (#1263)
+
+
+## 2.2.2
+
+### Fixes
+* Fixed bug in `WithinAbs::match()` failing spuriously (#1228)
+* Fixed clang-tidy diagnostic about virtual call in destructor (#1226)
+* Reduced the number of GCC warnings suppression leaking out of the header (#1090, #1091)
+  * Only `-Wparentheses` should be leaking now
+* Added upper bound on the time benchmark timer calibration is allowed to take (#1237)
+  * On platforms where `std::chrono::high_resolution_clock`'s resolution is low, the calibration would appear stuck
+* Fixed compilation error when stringifying static arrays of `unsigned char`s (#1238)
+
+### Improvements
+* XML encoder now hex-encodes invalid UTF-8 sequences (#1207)
+  * This affects xml and junit reporters
+  * Some invalid UTF-8 parts are left as is, e.g. surrogate pairs. This is because certain extensions of UTF-8 allow them, such as WTF-8.
+* CLR objects (`T^`) can now be stringified (#1216)
+  * This affects code compiled as C++/CLI
+* Added `PredicateMatcher`, a matcher that takes an arbitrary predicate function (#1236)
+  * See [documentation for details](https://github.com/catchorg/Catch2/blob/master/docs/matchers.md)
+
+### Others
+* Modified CMake-installed pkg-config to allow `#include <catch.hpp>`(#1239)
+  * The plans to standardize on `#include <catch2/catch.hpp>` are still in effect
+
+
+## 2.2.1
+
+### Fixes
+* Fixed compilation error when compiling Catch2 with `std=c++17` against libc++ (#1214)
+  * Clara (Catch2's CLI parsing library) used `std::optional` without including it explicitly
+* Fixed Catch2 return code always being 0 (#1215)
+  * In the words of STL, "We feel superbad about letting this in"
+
+
+## 2.2.0
+
+### Fixes
+* Hidden tests are not listed by default when listing tests (#1175)
+  * This makes `catch_discover_tests` CMake script work better
+* Fixed regression that meant `<windows.h>` could potentially not be included properly (#1197)
+* Fixed installing `Catch2ConfigVersion.cmake` when Catch2 is a subproject.
+
+### Improvements
+* Added an option to warn (+ exit with error) when no tests were ran (#1158)
+  * Use as `-w NoTests`
+* Added provisional support for Emscripten (#1114)
+* [Added a way to override the fallback stringifier](https://github.com/catchorg/Catch2/blob/master/docs/configuration.md#fallback-stringifier) (#1024)
+  * This allows project's own stringification machinery to be easily reused for Catch
+* `Catch::Session::run()` now accepts `char const * const *`, allowing it to accept array of string literals (#1031, #1178)
+  * The embedded version of Clara was bumped to v1.1.3
+* Various minor performance improvements
+* Added support for DJGPP DOS crosscompiler (#1206)
+
+
+## 2.1.2
+
+### Fixes
+* Fixed compilation error with `-fno-rtti` (#1165)
+* Fixed NoAssertion warnings
+* `operator<<` is used before range-based stringification (#1172)
+* Fixed `-Wpedantic` warnings (extra semicolons and binary literals) (#1173)
+
+
+### Improvements
+* Added `CATCH_VERSION_{MAJOR,MINOR,PATCH}` macros (#1131)
+* Added `BrightYellow` colour for use in reporters (#979)
+  * It is also used by ConsoleReporter for reconstructed expressions
+
+### Other changes
+* Catch is now exported as a CMake package and linkable target (#1170)
+
+## 2.1.1
+
+### Improvements
 * Static arrays are now properly stringified like ranges across MSVC/GCC/Clang
 * Embedded newer version of Clara -- v1.1.1
   * This should fix some warnings dragged in from Clara
 * MSVC's CLR exceptions are supported
 
 
-## Fixes
+### Fixes
 * Fixed compilation when comparison operators do not return bool (#1147)
 * Fixed CLR exceptions blowing up the executable during translation (#1138)
 
 
-## Other changes
+### Other changes
 * Many CMake changes
   * `NO_SELFTEST` option is deprecated, use `BUILD_TESTING` instead.
   * Catch specific CMake options were prefixed with `CATCH_` for namespacing purposes
@@ -22,9 +362,9 @@
 
 
 
-# 2.1.0
+## 2.1.0
 
-## Improvements
+### Improvements
 * Various performance improvements
   * On top of the performance regression fixes
 * Experimental support for PCH was added (#1061)
@@ -34,7 +374,7 @@
   * Bugs in g++ 4.x and 5.x mean that some of them have to be left in
 
 
-## Fixes
+### Fixes
 * Fixed performance regression from Catch classic
   * One of the performance improvement patches for Catch classic was not applied to Catch2
 * Fixed platform detection for iOS (#1084)
@@ -47,7 +387,7 @@
 * Fixed `std::uncaught_exception` deprecation warning (#1124)
 
 
-## New features
+### New features
 * New Matchers
   * Regex matcher for strings, `Matches`.
   * Set-equal matcher for vectors, `UnorderedEquals`
@@ -56,15 +396,15 @@
   * Containers are objects that respond to ADL `begin(T)` and `end(T)`.
 
 
-## Other changes
+### Other changes
 * Reporters will now be versioned in the `single_include` folder to ensure their compatibility with the last released version
 
 
 
 
-# 2.0.1
+## 2.0.1
 
-## Breaking changes
+### Breaking changes
 * Removed C++98 support
 * Removed legacy reporter support
 * Removed legacy generator support
@@ -94,7 +434,7 @@
   * `INFINITY == Approx(INFINITY)` returns true
 
 
-## Improvements
+### Improvements
 * Reporters and Listeners can be defined in files different from the main file
   * The file has to define `CATCH_CONFIG_EXTERNAL_INTERFACES` before including catch.hpp.
 * Errors that happen during set up before main are now caught and properly reported once main is entered
@@ -128,7 +468,7 @@
 * Add `pkg-config` support to CMake install command
 
 
-## Fixes
+### Fixes
 * Don't use console colour if running in XCode
 * Explicit constructor in reporter base class
 * Swept out `-Wweak-vtables`, `-Wexit-time-destructors`, `-Wglobal-constructors` warnings
@@ -140,7 +480,7 @@
 * Suppressed C4061 warning under MSVC
 
 
-## Internal changes
+### Internal changes
 * The development version now uses .cpp files instead of header files containing implementation.
   * This makes partial rebuilds much faster during development
 * The expression decomposition layer has been rewritten
@@ -148,13 +488,33 @@
 * New library (TextFlow) is used for formatting text to output
 
 
-# Older versions
+## Older versions
 
-## 1.11.x
+### 1.12.x
 
-### 1.11.0
+#### 1.12.2
+##### Fixes
+* Fixed missing <cassert> include
 
-#### Fixes
+#### 1.12.1
+
+##### Fixes
+* Fixed deprecation warning in `ScopedMessage::~ScopedMessage`
+* All uses of `min` or `max` identifiers are now wrapped in parentheses
+  * This avoids problems when Windows headers define `min` and `max` macros
+
+#### 1.12.0
+
+##### Fixes
+* Fixed compilation for strict C++98 mode (ie not gnu++98) and older compilers (#1103)
+* `INFO` messages are included in the `xml` reporter output even without `-s` specified.
+
+
+### 1.11.x
+
+#### 1.11.0
+
+##### Fixes
 * The original expression in `REQUIRE_FALSE( expr )` is now reporter properly as `!( expr )` (#1051)
   * Previously the parentheses were missing and `x != y` would be expanded as `!x != x`
 * `Approx::Margin` is now inclusive (#952)
@@ -162,7 +522,7 @@
   * This means that `REQUIRE( 0.25f == Approx( 0.0f ).margin( 0.25f ) )` passes, instead of fails
 * `RandomNumberGenerator::result_type` is now unsigned (#1050)
 
-#### Improvements
+##### Improvements
 * `__JETBRAINS_IDE__` macro handling is now CLion version specific (#1017)
   * When CLion 2017.3 or newer is detected, `__COUNTER__` is used instead of
 * TeamCity reporter now explicitly flushes output stream after each report (#1057)
@@ -170,35 +530,35 @@
 * `ParseAndAddCatchTests` now can add test files as dependency to CMake configuration
   * This means you do not have to manually rerun CMake configuration step to detect new tests
 
-## 1.10.x
+### 1.10.x
 
-### 1.10.0
+#### 1.10.0
 
-#### Fixes
+##### Fixes
 * Evaluation layer has been rewritten (backported from Catch 2)
   * The new layer is much simpler and fixes some issues (#981)
 * Implemented workaround for VS 2017 raw string literal stringification bug (#995)
 * Fixed interaction between `[!shouldfail]` and `[!mayfail]` tags and sections
   * Previously sections with failing assertions would be marked as failed, not failed-but-ok
 
-#### Improvements
+##### Improvements
 * Added [libidentify](https://github.com/janwilmans/LibIdentify) support
 * Added "wait-for-keypress" option
 
-## 1.9.x
+### 1.9.x
 
-### 1.9.6
+#### 1.9.6
 
-#### Improvements
+##### Improvements
 * Catch's runtime overhead has been significantly decreased (#937, #939)
 * Added `--list-extra-info` cli option (#934).
   * It lists all tests together with extra information, ie filename, line number and description.
 
 
 
-### 1.9.5
+#### 1.9.5
 
-#### Fixes
+##### Fixes
 * Truthy expressions are now reconstructed properly, not as booleans (#914)
 * Various warnings are no longer erroneously suppressed in test files (files that include `catch.hpp`, but do not define `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`) (#871)
 * Catch no longer fails to link when main is compiled as C++, but linked against Objective-C (#855)
@@ -206,35 +566,35 @@
   * Previously any GCC with minor version less than 3 would be incorrectly classified as not supporting `__COUNTER__`.
 * Suppressed C4996 warning caused by upcoming updated to MSVC 2017, marking `std::uncaught_exception` as deprecated. (#927)
 
-#### Improvements
+##### Improvements
 * CMake integration script now incorporates debug messages and registers tests in an improved way (#911)
 * Various documentation improvements
 
 
 
-### 1.9.4
+#### 1.9.4
 
-#### Fixes
+##### Fixes
 * `CATCH_FAIL` macro no longer causes compilation error without variadic macro support
 * `INFO` messages are no longer cleared after being reported once
 
-#### Improvements and minor changes
+##### Improvements and minor changes
 * Catch now uses `wmain` when compiled under Windows and `UNICODE` is defined.
   * Note that Catch still officially supports only ASCII
 
-### 1.9.3
+#### 1.9.3
 
-#### Fixes
+##### Fixes
 * Completed the fix for (lack of) uint64_t in earlier Visual Studios
 
-### 1.9.2
+#### 1.9.2
 
-#### Improvements and minor changes
+##### Improvements and minor changes
 * All of `Approx`'s member functions now accept strong typedefs in C++11 mode (#888)
   * Previously `Approx::scale`, `Approx::epsilon`, `Approx::margin` and `Approx::operator()` didn't.
 
 
-#### Fixes
+##### Fixes
 * POSIX signals are now disabled by default under QNX (#889)
   * QNX does not support current enough (2001) POSIX specification
 * JUnit no longer counts exceptions as failures if given test case is marked as ok to fail.
@@ -242,22 +602,22 @@
 * Catch no longer attempts to define `uint64_t` on windows (#862)
   * This was causing trouble when compiled under Cygwin
 
-#### Other
+##### Other
 * Catch is now compiled under MSVC 2017 using `std:c++latest` (C++17 mode) in CI
 * We now provide cmake script that autoregisters Catch tests into ctest.
   * See `contrib` folder.
 
 
-### 1.9.1
+#### 1.9.1
 
-#### Fixes
+##### Fixes
 * Unexpected exceptions are no longer ignored by default (#885, #887)
 
 
-### 1.9.0
+#### 1.9.0
 
 
-#### Improvements and minor changes
+##### Improvements and minor changes
 * Catch no longer attempts to ensure the exception type passed by user in `REQUIRE_THROWS_AS` is a constant reference.
   * It was causing trouble when `REQUIRE_THROWS_AS` was used inside templated functions
   * This actually reverts changes made in v1.7.2
@@ -271,7 +631,7 @@
 * When Catch is compiled using C++11, `Approx` is now constructible with anything that can be explicitly converted to `double`.
 * Captured messages are now printed on unexpected exceptions
 
-#### Fixes:
+##### Fixes:
 * Clang's `-Wexit-time-destructors` should be suppressed for Catch's internals
 * GCC's `-Wparentheses` is now suppressed for all TU's that include `catch.hpp`.
   * This is functionally a revert of changes made in 1.8.0, where we tried using `_Pragma` based suppression. This should have kept the suppression local to Catch's assertions, but bugs in GCC's handling of `_Pragma`s in C++ mode meant that it did not always work.
@@ -280,18 +640,18 @@
   * [Details can be found in documentation](configuration.md#catch_config_cpp11_stream_insertable_check)
 
 
-#### Other notes:
+##### Other notes:
 * We have added VS 2017 to our CI
 * Work on Catch 2 should start soon
 
 
 
-## 1.8.x
+### 1.8.x
 
-### 1.8.2
+#### 1.8.2
 
 
-#### Improvements and minor changes
+##### Improvements and minor changes
 * TAP reporter now behaves as if `-s` was always set
   * This should be more consistent with the protocol desired behaviour.
 * Compact reporter now obeys `-d yes` argument (#780)
@@ -305,7 +665,7 @@
   * Listeners provide a way to hook into events generated by running your tests, including start and end of run, every test case, every section and every assertion.
 
 
-#### Fixes:
+##### Fixes:
 * Catch no longer attempts to reconstruct expression that led to a fatal error  (#810)
   * This fixes possible signal/SEH loop when processing expressions, where the signal was triggered by expression decomposition.
 * Fixed (C4265) missing virtual destructor warning in Matchers (#844)
@@ -322,21 +682,21 @@
 * Regression in Objective-C bindings (Matchers) fixed (#854)
 
 
-#### Other notes:
+##### Other notes:
 * We have added VS 2013 and 2015 to our CI
 * Catch Classic (1.x.x) now contains its own, forked, version of Clara (the argument parser).
 
 
 
-### 1.8.1
+#### 1.8.1
 
-#### Fixes
+##### Fixes
 
 Cygwin issue with `gettimeofday` - `#define` was not early enough
 
-### 1.8.0
+#### 1.8.0
 
-#### New features/ minor changes
+##### New features/ minor changes
 
 * Matchers have new, simpler (and documented) interface.
   * Catch provides string and vector matchers.
@@ -356,33 +716,33 @@
 * `Approx` now supports an optional margin of absolute error
   * It has also received [new documentation](assertions.md#top).
 
-#### Fixes
+##### Fixes
 * Silenced C4312 ("conversion from int to 'ClassName *") warnings in the evaluate layer.
 * Fixed C4512 ("assignment operator could not be generated") warnings under VS2013.
 * Cygwin compatibility fixes
   * Signal handling is no longer compiled by default.
   * Usage of `gettimeofday` inside Catch should no longer cause compilation errors.
-* Improved `-Wparentheses` supression for gcc (#674)
-  * When compiled with gcc 4.8 or newer, the supression is localized to assertions only
+* Improved `-Wparentheses` suppression for gcc (#674)
+  * When compiled with gcc 4.8 or newer, the suppression is localized to assertions only
   * Otherwise it is supressed for the whole TU
 * Fixed test spec parser issue (with escapes in multiple names)
 
-#### Other
+##### Other
 * Various documentation fixes and improvements
 
 
-## 1.7.x
+### 1.7.x
 
-### 1.7.2
+#### 1.7.2
 
-#### Fixes and minor improvements
+##### Fixes and minor improvements
 Xml:
 
 (technically the first two are breaking changes but are also fixes and arguably break few if any people)
 * C-escape control characters instead of XML encoding them (which requires XML 1.1)
 * Revert XML output to XML 1.0
 * Can provide stylesheet references by extending the XML reporter
-* Added description and tags attribites to XML Reporter
+* Added description and tags attributes to XML Reporter
 * Tags are closed and the stream flushed more eagerly to avoid stdout interpolation
 
 
@@ -394,9 +754,9 @@
 * Silenced a few more warnings in different circumstances
 * Travis improvements
 
-### 1.7.1
+#### 1.7.1
 
-#### Fixes:
+##### Fixes:
 * Fixed inconsistency in defining `NOMINMAX` and `WIN32_LEAN_AND_MEAN` inside `catch.hpp`.
 * Fixed SEH-related compilation error under older MinGW compilers, by making Windows SEH handling opt-in for compilers other than MSVC.
   * For specifics, look into the [documentation](configuration.md#top).
@@ -406,9 +766,9 @@
 * Fixed possible infinite recursion in Windows SEH.
 * Fixed possible compilation error caused by Catch's operator overloads being ambiguous in regards to user-defined templated operators.
 
-### 1.7.0
+#### 1.7.0
 
-#### Features/ Changes:
+##### Features/ Changes:
 * Catch now runs significantly faster for passing tests
   * Microbenchmark focused on Catch's overhead went from ~3.4s to ~0.7s.
   * Real world test using [JSON for Modern C++](https://github.com/nlohmann/json)'s test suite went from ~6m 25s to ~4m 14s.
@@ -422,30 +782,30 @@
 * Certain characters (space, tab, etc) are now pretty printed.
   * This means that a `char c = ' '; REQUIRE(c == '\t');` would be printed as `' ' == '\t'`, instead of ` == 9`.
 
-#### Fixes:
+##### Fixes:
 * Text formatting no longer attempts to access out-of-bounds characters under certain conditions.
 * THROW family of assertions no longer trigger `-Wunused-value` on expressions containing explicit cast.
 * Breaking into debugger under OS X works again and no longer required `DEBUG` to be defined.
 * Compilation no longer breaks under certain compiler if a lambda is used inside assertion macro.
 
-#### Other:
+##### Other:
 * Catch's CMakeLists now defines install command.
 * Catch's CMakeLists now generates projects with warnings enabled.
 
 
-## 1.6.x
+### 1.6.x
 
-### 1.6.1
+#### 1.6.1
 
-#### Features/ Changes:
+##### Features/ Changes:
 * Catch now supports breaking into debugger on Linux
 
-#### Fixes:
+##### Fixes:
 * Generators no longer leak memory (generators are still unsupported in general)
 * JUnit reporter now reports UTC timestamps, instead of "tbd"
 * `CHECK_THAT` macro is now properly defined as `CATCH_CHECK_THAT` when using `CATCH_` prefixed macros
 
-#### Other:
+##### Other:
 * Types with overloaded `&&` operator are no longer evaluated twice when used in an assertion macro.
 * The use of `__COUNTER__` is supressed when Catch is parsed by CLion
   * This change is not active when compiling a binary
@@ -455,28 +815,28 @@
   * This can be disabled if needed, see [documentation](configuration.md#top) for details.
 
 
-### 1.6.0
+#### 1.6.0
 
-#### Cmake/ projects:
+##### Cmake/ projects:
 * Moved CMakeLists.txt to root, made it friendlier for CLion and generating XCode and VS projects, and removed the manually maintained XCode and VS projects.
 
-#### Features/ Changes:
+##### Features/ Changes:
 * Approx now supports `>=` and `<=`
 * Can now use `\` to escape chars in test names on command line
 * Standardize C++11 feature toggles
 
-#### Fixes:
+##### Fixes:
 * Blue shell colour
 * Missing argument to `CATCH_CHECK_THROWS`
 * Don't encode extended ASCII in XML
 * use `std::shuffle` on more compilers (fixes deprecation warning/error)
 * Use `__COUNTER__` more consistently (where available)
 
-#### Other:
+##### Other:
 * Tweaks and changes to scripts - particularly for Approval test - to make them more portable
 
 
-# Even Older versions
+## Even Older versions
 Release notes were not maintained prior to v1.6.0, but you should be able to work them out from the Git history
 
 ---
diff --git a/docs/release-process.md b/docs/release-process.md
index 433777b..412cf2d 100644
--- a/docs/release-process.md
+++ b/docs/release-process.md
@@ -1,18 +1,18 @@
 <a id="top"></a>
 # How to release
 
-When enough changes have accumulated, it is time to release new version of Catch. This document describes the proces in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
+When enough changes have accumulated, it is time to release new version of Catch. This document describes the process in doing so, that no steps are forgotten. Note that all referenced scripts can be found in the `scripts/` directory.
 
-## Neccessary steps
+## Necessary steps
 
-These steps are neccessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
+These steps are necessary and have to be performed before each new release. They serve to make sure that the new release is correct and linked-to from the standard places.
 
 
-### Approval testing
+### Testing
 
-Catch's releases are primarily validated against output from previous release, stored in `projects/SelfTest/Baselines`. To validate current sources, build the SelfTest binary and pass it to the `approvalTests.py` script: `approvalTests.py <path/to/SelfTest>`.
-
-There should be no differences, as Approval tests should be updated when changes to Catch are made, but if there are, then they need to be manually reviewed and either approved (using `approve.py`) or Catch requires other fixes.
+All of the tests are currently run in our CI setup based on TravisCI and
+AppVeyor. As long as the last commit tested green, the release can
+proceed.
 
 
 ### Incrementing version number
@@ -27,7 +27,7 @@
 
 ### Release notes
 
-Once a release is ready, release notes need to be written. They should summarize changes done since last release. For rough idea of expected notes see previous releases. Once written, release notes should be placed in `docs/release-notes.md`.
+Once a release is ready, release notes need to be written. They should summarize changes done since last release. For rough idea of expected notes see previous releases. Once written, release notes should be added to `docs/release-notes.md`.
 
 
 ### Commit and push update to GitHub
@@ -43,23 +43,30 @@
 Single header version of `catch.hpp` *needs* to be attached as a binary,
 as that is where the official download link links to. Preferably
 it should use linux line endings. All non-bundled reporters (Automake,
-TAP, TeamCity) should also be attached as binaries, as they are dependent
-on a specific version of the single-include header.
+TAP, TeamCity) should also be attached as binaries, as they might be
+dependent on a specific version of the single-include header.
 
+Since 2.5.0, the release tag and the "binaries" (headers) should be PGP
+signed.
 
-## Optional steps
+#### Signing a tag
 
-The following steps are optional, and do not have to be performed when releasing new version of Catch. However, they *should* happen, but they can happen the next day without losing anything significant.
+To create a signed tag, use `git tag -s <VERSION>`, where `<VERSION>`
+is the version being released, e.g. `git tag -s v2.6.0`.
 
+Use the version name as the short message and the release notes as
+the body (long) message.
 
-### vcpkg update
+#### Signing the headers
 
-Catch is maintaining its own port in Microsoft's package manager [vcpkg](https://github.com/Microsoft/vcpkg). This means that when new version of Catch is released, it should be posted there as well. `updateVcpkgPackage.py` can do a lot of neccessary work for you, it creates a branch and commits neccessary changes. You should review these changes, push and open a PR against vcpkg's upstream.
+This will create ASCII-armored signatures for the headers that are
+uploaded to the GitHub release:
 
-Note that the script assumes you have your fork of vcpkg checked out in a directory next to the directory where you have checked out Catch, like so:
 ```
-GitHub
-    Catch
-    vcpkg
+$ gpg2 --armor --output catch.hpp.asc --detach-sig catch.hpp
+$ gpg2 --armor --output catch_reporter_automake.hpp.asc --detach-sig catch_reporter_automake.hpp
+$ gpg2 --armor --output catch_reporter_teamcity.hpp.asc --detach-sig catch_reporter_teamcity.hpp
+$ gpg2 --armor --output catch_reporter_tap.hpp.asc --detach-sig catch_reporter_tap.hpp
 ```
 
+_GPG does not support signing multiple files in single invocation._
diff --git a/docs/reporters.md b/docs/reporters.md
index 78e78ee..32b3419 100644
--- a/docs/reporters.md
+++ b/docs/reporters.md
@@ -25,8 +25,8 @@
 There are a few additional reporters, for specific build systems, in the Catch repository (in `include\reporters`) which you can `#include` in your project if you would like to make use of them.
 Do this in one source file - the same one you have `CATCH_CONFIG_MAIN` or `CATCH_CONFIG_RUNNER`.
 
-* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands.
-Use this when building as part of a TeamCity build to see results as they happen.
+* `teamcity` writes the native, streaming, format that [TeamCity](https://www.jetbrains.com/teamcity/) understands. 
+Use this when building as part of a TeamCity build to see results as they happen ([code example](../examples/207-Rpt-TeamCityReporter.cpp)).
 * `tap` writes in the TAP ([Test Anything Protocol](https://en.wikipedia.org/wiki/Test_Anything_Protocol)) format.
 * `automake` writes in a format that correspond to [automake  .trs](https://www.gnu.org/software/automake/manual/html_node/Log-files-generation-and-test-results-recording.html) files
 
diff --git a/docs/test-cases-and-sections.md b/docs/test-cases-and-sections.md
index 68944f5..62a805f 100644
--- a/docs/test-cases-and-sections.md
+++ b/docs/test-cases-and-sections.md
@@ -1,6 +1,12 @@
 <a id="top"></a>
 # Test cases and sections
 
+**Contents**<br>
+[Tags](#tags)<br>
+[Tag aliases](#tag-aliases)<br>
+[BDD-style test cases](#bdd-style-test-cases)<br>
+[Type parametrised test cases](#type-parametrised-test-cases)<br>
+
 While Catch fully supports the traditional, xUnit, style of class-based fixtures containing test case methods this is not the preferred style.
 
 Instead Catch provides a powerful mechanism for nesting test case sections within a test case. For a more detailed discussion see the [tutorial](tutorial.md#test-cases-and-sections).
@@ -20,10 +26,10 @@
 
 As an example - given the following test cases:
 
-	TEST_CASE( "A", "[widget]" ) { /* ... */ }
-	TEST_CASE( "B", "[widget]" ) { /* ... */ }
-	TEST_CASE( "C", "[gadget]" ) { /* ... */ }
-	TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
+    TEST_CASE( "A", "[widget]" ) { /* ... */ }
+    TEST_CASE( "B", "[widget]" ) { /* ... */ }
+    TEST_CASE( "C", "[gadget]" ) { /* ... */ }
+    TEST_CASE( "D", "[widget][gadget]" ) { /* ... */ }
 
 The tag expression, ```"[widget]"``` selects A, B & D. ```"[gadget]"``` selects C & D. ```"[widget][gadget]"``` selects just D and ```"[widget],[gadget]"``` selects all four test cases.
 
@@ -37,7 +43,7 @@
 
 * `[!hide]` or `[.]` - causes test cases to be skipped from the default list (i.e. when no test cases have been explicitly selected through tag expressions or name wildcards). The hide tag is often combined with another, user, tag (for example `[.][integration]` - so all integration tests are excluded from the default run but can be run by passing `[integration]` on the command line). As a short-cut you can combine these by simply prefixing your user tag with a `.` - e.g. `[.integration]`. Because the hide tag has evolved to have several forms, all forms are added as tags if you use one of them.
 
-* `[!throws]`	- lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
+* `[!throws]` - lets Catch know that this test is likely to throw an exception even if successful. This causes the test to be excluded when running with `-e` or `--nothrow`.
 
 * `[!mayfail]` - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
 
@@ -55,11 +61,11 @@
 
 Between tag expressions and wildcarded test names (as well as combinations of the two) quite complex patterns can be constructed to direct which test cases are run. If a complex pattern is used often it is convenient to be able to create an alias for the expression. This can be done, in code, using the following form:
 
-	CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
+    CATCH_REGISTER_TAG_ALIAS( <alias string>, <tag expression> )
 
 Aliases must begin with the `@` character. An example of a tag alias is:
 
-	CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
+    CATCH_REGISTER_TAG_ALIAS( "[@nhf]", "[failing]~[.]" )
 
 Now when `[@nhf]` is used on the command line this matches all tests that are tagged `[failing]`, but which are not also hidden.
 
@@ -86,6 +92,105 @@
 
 Other than the additional prefixes and the formatting in the console reporter these macros behave exactly as ```TEST_CASE```s and ```SECTION```s. As such there is nothing enforcing the correct sequencing of these macros - that's up to the programmer!
 
+## Type parametrised test cases
+
+In addition to `TEST_CASE`s, Catch2 also supports test cases parametrised
+by types, in the form of `TEMPLATE_TEST_CASE` and
+`TEMPLATE_PRODUCT_TEST_CASE`.
+
+* **TEMPLATE_TEST_CASE(** _test name_ , _tags_,  _type1_, _type2_, ..., _typen_ **)**
+
+_test name_ and _tag_ are exactly the same as they are in `TEST_CASE`,
+with the difference that the tag string must be provided (however, it
+can be empty). _type1_ through _typen_ is the list of types for which
+this test case should run, and, inside the test code, the current type
+is available as the `TestType` type.
+
+Because of limitations of the C++ preprocessor, if you want to specify
+a type with multiple template parameters, you need to enclose it in
+parentheses, e.g. `std::map<int, std::string>` needs to be passed as
+`(std::map<int, std::string>)`.
+
+Example:
+```cpp
+TEMPLATE_TEST_CASE( "vectors can be sized and resized", "[vector][template]", int, std::string, (std::tuple<int,float>) ) {
+
+    std::vector<TestType> v( 5 );
+
+    REQUIRE( v.size() == 5 );
+    REQUIRE( v.capacity() >= 5 );
+
+    SECTION( "resizing bigger changes size and capacity" ) {
+        v.resize( 10 );
+
+        REQUIRE( v.size() == 10 );
+        REQUIRE( v.capacity() >= 10 );
+    }
+    SECTION( "resizing smaller changes size but not capacity" ) {
+        v.resize( 0 );
+
+        REQUIRE( v.size() == 0 );
+        REQUIRE( v.capacity() >= 5 );
+
+        SECTION( "We can use the 'swap trick' to reset the capacity" ) {
+            std::vector<TestType> empty;
+            empty.swap( v );
+
+            REQUIRE( v.capacity() == 0 );
+        }
+    }
+    SECTION( "reserving smaller does not change size or capacity" ) {
+        v.reserve( 0 );
+
+        REQUIRE( v.size() == 5 );
+        REQUIRE( v.capacity() >= 5 );
+    }
+}
+```
+
+* **TEMPLATE_PRODUCT_TEST_CASE(** _test name_ , _tags_, (_template-type1_, _template-type2_, ..., _template-typen_), (_template-arg1_, _template-arg2_, ..., _template-argm_) **)**
+
+_template-type1_ through _template-typen_ is list of template template
+types which should be combined with each of _template-arg1_ through
+ _template-argm_, resulting in _n * m_ test cases. Inside the test case,
+the resulting type is available under the name of `TestType`.
+
+To specify more than 1 type as a single _template-type_ or _template-arg_,
+you must enclose the types in an additional set of parentheses, e.g.
+`((int, float), (char, double))` specifies 2 template-args, each
+consisting of 2 concrete types (`int`, `float` and `char`, `double`
+respectively). You can also omit the outer set of parentheses if you
+specify only one type as the full set of either the _template-types_,
+or the _template-args_.
+
+
+Example:
+```cpp
+template< typename T>
+struct Foo {
+    size_t size() {
+        return 0;
+    }
+};
+
+TEMPLATE_PRODUCT_TEST_CASE("A Template product test case", "[template][product]", (std::vector, Foo), (int, float)) {
+    TestType x;
+    REQUIRE(x.size() == 0);
+}
+```
+
+You can also have different arities in the _template-arg_ packs:
+```cpp
+TEMPLATE_PRODUCT_TEST_CASE("Product with differing arities", "[template][product]", std::tuple, (int, (int, double), (int, double, float))) {
+    TestType x;
+    REQUIRE(std::tuple_size<TestType>::value >= 1);
+}
+```
+
+_While there is an upper limit on the number of types you can specify
+in single `TEMPLATE_TEST_CASE` or `TEMPLATE_PRODUCT_TEST_CASE`, the limit
+is very high and should not be encountered in practice._
+
 ---
 
 [Home](Readme.md#top)
diff --git a/docs/test-fixtures.md b/docs/test-fixtures.md
index 1dc7bab..6b29ce6 100644
--- a/docs/test-fixtures.md
+++ b/docs/test-fixtures.md
@@ -30,6 +30,60 @@
 
 The two test cases here will create uniquely-named derived classes of UniqueTestsFixture and thus can access the `getID()` protected method and `conn` member variables. This ensures that both the test cases are able to create a DBConnection using the same method (DRY principle) and that any ID's created are unique such that the order that tests are executed does not matter.
 
+
+Catch2 also provides `TEMPLATE_TEST_CASE_METHOD` and
+`TEMPLATE_PRODUCT_TEST_CASE_METHOD` that can be used together
+with templated fixtures and templated template fixtures to perform
+tests for multiple different types. Unlike `TEST_CASE_METHOD`,
+`TEMPLATE_TEST_CASE_METHOD` and `TEMPLATE_PRODUCT_TEST_CASE_METHOD` do
+require the tag specification to be non-empty, as it is followed by
+further macro arguments.
+
+Also note that, because of limitations of the C++ preprocessor, if you
+want to specify a type with multiple template parameters, you need to
+enclose it in parentheses, e.g. `std::map<int, std::string>` needs to be
+passed as `(std::map<int, std::string>)`.
+In the case of `TEMPLATE_PRODUCT_TEST_CASE_METHOD`, if a member of the
+type list should consist of more than single type, it needs to be enclosed
+in another pair of parentheses, e.g. `(std::map, std::pair)` and
+`((int, float), (char, double))`.
+
+Example:
+```cpp
+template< typename T >
+struct Template_Fixture {
+    Template_Fixture(): m_a(1) {}
+
+    T m_a;
+};
+
+TEMPLATE_TEST_CASE_METHOD(Template_Fixture,"A TEMPLATE_TEST_CASE_METHOD based test run that succeeds", "[class][template]", int, float, double) {
+    REQUIRE( Template_Fixture<TestType>::m_a == 1 );
+}
+
+template<typename T>
+struct Template_Template_Fixture {
+    Template_Template_Fixture() {}
+
+    T m_a;
+};
+
+template<typename T>
+struct Foo_class {
+    size_t size() {
+        return 0;
+    }
+};
+
+TEMPLATE_PRODUCT_TEST_CASE_METHOD(Template_Template_Fixture, "A TEMPLATE_PRODUCT_TEST_CASE_METHOD based test succeeds", "[class][template]", (Foo_class, std::vector), int) {
+    REQUIRE( Template_Template_Fixture<TestType>::m_a.size() == 0 );
+}
+```
+
+_While there is an upper limit on the number of types you can specify
+in single `TEMPLATE_TEST_CASE_METHOD` or `TEMPLATE_PRODUCT_TEST_CASE_METHOD`,
+the limit is very high and should not be encountered in practice._
+
 ---
 
 [Home](Readme.md#top)
diff --git a/docs/tostring.md b/docs/tostring.md
index 568c1c2..933f2e6 100644
--- a/docs/tostring.md
+++ b/docs/tostring.md
@@ -1,6 +1,12 @@
 <a id="top"></a>
 # String conversions
 
+**Contents**<br>
+[operator << overload for std::ostream](#operator--overload-for-stdostream)<br>
+[Catch::StringMaker specialisation](#catchstringmaker-specialisation)<br>
+[Catch::is_range specialisation](#catchis_range-specialisation)<br>
+[Exceptions](#exceptions)<br>
+
 Catch needs to be able to convert types you use in assertions and logging expressions into strings (for logging and reporting purposes).
 Most built-in or std types are supported out of the box but there are two ways that you can tell Catch how to convert your own types (or other, third-party types) into strings.
 
@@ -10,30 +16,30 @@
 
 ```
 std::ostream& operator << ( std::ostream& os, T const& value ) {
-	os << convertMyTypeToString( value );
-	return os;
+    os << convertMyTypeToString( value );
+    return os;
 }
 ```
 
 (where ```T``` is your type and ```convertMyTypeToString``` is where you'll write whatever code is necessary to make your type printable - it doesn't have to be in another function).
 
-You should put this function in the same namespace as your type and have it declared before including Catch's header.
+You should put this function in the same namespace as your type, or the global namespace, and have it declared before including Catch's header.
 
-## Catch::StringMaker<T> specialisation
+## Catch::StringMaker specialisation
 If you don't want to provide an ```operator <<``` overload, or you want to convert your type differently for testing purposes, you can provide a specialization for `Catch::StringMaker<T>`:
 
 ```
 namespace Catch {
-	template<>
+    template<>
     struct StringMaker<T> {
-    	static std::string convert( T const& value ) {
-        	return convertMyTypeToString( value );
+        static std::string convert( T const& value ) {
+            return convertMyTypeToString( value );
         }
     };
 }
 ```
 
-## Catch::is_range<T> specialisation
+## Catch::is_range specialisation
 As a fallback, Catch attempts to detect if the type can be iterated
 (`begin(T)` and `end(T)` are valid) and if it can be, it is stringified
 as a range. For certain types this can lead to infinite recursion, so
@@ -56,7 +62,7 @@
 
 ```
 CATCH_TRANSLATE_EXCEPTION( MyType& ex ) {
-	return ex.message();
+    return ex.message();
 }
 ```
 
diff --git a/docs/tutorial.md b/docs/tutorial.md
index d55355c..7c0f814 100644
--- a/docs/tutorial.md
+++ b/docs/tutorial.md
@@ -8,24 +8,31 @@
 [Test cases and sections](#test-cases-and-sections)<br>
 [BDD-Style](#bdd-style)<br>
 [Scaling up](#scaling-up)<br>
+[Type parametrised test cases](#type-parametrised-test-cases)<br>
 [Next steps](#next-steps)<br>
 
 ## Getting Catch2
 
-The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/CatchOrg/Catch2/master/single_include/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
+The simplest way to get Catch2 is to download the latest [single header version](https://raw.githubusercontent.com/catchorg/Catch2/master/single_include/catch2/catch.hpp). The single header is generated by merging a set of individual headers but it is still just normal source code in a header file.
+
+Alternative ways of getting Catch2 include using your system package
+manager, or installing it using [its CMake package](cmake-integration.md#installing-catch2-from-git-repository).
 
 The full source for Catch2, including test projects, documentation, and other things, is hosted on GitHub. [http://catch-lib.net](http://catch-lib.net) will redirect you there.
 
 
 ## Where to put it?
 
-Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html). 
+Catch2 is header only. All you need to do is drop the file somewhere reachable from your project - either in some central location you can set your header search path to find, or directly into your project tree itself! This is a particularly good option for other Open-Source projects that want to use Catch for their test suite. See [this blog entry for more on that](http://www.levelofindirection.com/journal/2011/5/27/unit-testing-in-c-and-objective-c-just-got-ridiculously-easi.html).
 
 The rest of this tutorial will assume that the Catch2 single-include header (or the include folder) is available unqualified - but you may need to prefix it with a folder name if necessary.
 
+_If you have installed Catch2 from system package manager, or CMake
+package, you need to include the header as `#include <catch2/catch.hpp>`_
+
 ## Writing tests
 
-Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now). 
+Let's start with a really simple example ([code](../examples/010-TestCase.cpp)). Say you have written a function to calculate factorials and now you want to test it (let's leave aside TDD for now).
 
 ```c++
 unsigned int Factorial( unsigned int number ) {
@@ -116,31 +123,31 @@
 TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
 
     std::vector<int> v( 5 );
-    
+
     REQUIRE( v.size() == 5 );
     REQUIRE( v.capacity() >= 5 );
-    
+
     SECTION( "resizing bigger changes size and capacity" ) {
         v.resize( 10 );
-        
+
         REQUIRE( v.size() == 10 );
         REQUIRE( v.capacity() >= 10 );
     }
     SECTION( "resizing smaller changes size but not capacity" ) {
         v.resize( 0 );
-        
+
         REQUIRE( v.size() == 0 );
         REQUIRE( v.capacity() >= 5 );
     }
     SECTION( "reserving bigger changes capacity but not size" ) {
         v.reserve( 10 );
-        
+
         REQUIRE( v.size() == 5 );
         REQUIRE( v.capacity() >= 10 );
     }
     SECTION( "reserving smaller does not change size or capacity" ) {
         v.reserve( 0 );
-        
+
         REQUIRE( v.size() == 5 );
         REQUIRE( v.capacity() >= 5 );
     }
@@ -157,13 +164,13 @@
 ```c++
     SECTION( "reserving bigger changes capacity but not size" ) {
         v.reserve( 10 );
-        
+
         REQUIRE( v.size() == 5 );
         REQUIRE( v.capacity() >= 10 );
-    
+
         SECTION( "reserving smaller again does not change capacity" ) {
             v.reserve( 7 );
-            
+
             REQUIRE( v.capacity() >= 10 );
         }
     }
@@ -182,13 +189,13 @@
 
     GIVEN( "A vector with some items" ) {
         std::vector<int> v( 5 );
-        
+
         REQUIRE( v.size() == 5 );
         REQUIRE( v.capacity() >= 5 );
-        
+
         WHEN( "the size is increased" ) {
             v.resize( 10 );
-            
+
             THEN( "the size and capacity change" ) {
                 REQUIRE( v.size() == 10 );
                 REQUIRE( v.capacity() >= 10 );
@@ -196,7 +203,7 @@
         }
         WHEN( "the size is reduced" ) {
             v.resize( 0 );
-            
+
             THEN( "the size changes but not capacity" ) {
                 REQUIRE( v.size() == 0 );
                 REQUIRE( v.capacity() >= 5 );
@@ -204,7 +211,7 @@
         }
         WHEN( "more capacity is reserved" ) {
             v.reserve( 10 );
-            
+
             THEN( "the capacity changes but not the size" ) {
                 REQUIRE( v.size() == 5 );
                 REQUIRE( v.capacity() >= 10 );
@@ -212,7 +219,7 @@
         }
         WHEN( "less capacity is reserved" ) {
             v.reserve( 0 );
-            
+
             THEN( "neither size nor capacity are changed" ) {
                 REQUIRE( v.size() == 5 );
                 REQUIRE( v.capacity() >= 5 );
@@ -250,6 +257,17 @@
 Do not write your tests in header files!
 
 
+## Type parametrised test cases
+
+Test cases in Catch2 can be also parametrised by type, via the
+`TEMPLATE_TEST_CASE` and `TEMPLATE_PRODUCT_TEST_CASE` macros,
+which behave in the same way the `TEST_CASE` macro, but are run for
+every type or type combination.
+
+For more details, see our documentation on [test cases and
+sections](test-cases-and-sections.md#type-parametrised-test-cases).
+
+
 ## Next steps
 
 This has been a brief introduction to get you up and running with Catch, and to point out some of the key differences between Catch and other frameworks you may already be familiar with. This will get you going quite far already and you are now in a position to dive in and write some tests.
diff --git a/docs/why-catch.md b/docs/why-catch.md
index 45f58a6..86cc55b 100644
--- a/docs/why-catch.md
+++ b/docs/why-catch.md
@@ -6,7 +6,7 @@
 [Google Test](http://code.google.com/p/googletest/),
 [Boost.Test](http://www.boost.org/doc/libs/1_49_0/libs/test/doc/html/index.html),
 [CppUnit](http://sourceforge.net/apps/mediawiki/cppunit/index.php?title=Main_Page),
-[Cute](http://r2.ifs.hsr.ch/cute),
+[Cute](http://www.cute-test.com),
 [many, many more](http://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C.2B.2B).
 
 So what does Catch bring to the party that differentiates it from these? Apart from a Catchy name, of course.
diff --git a/examples/000-CatchMain.cpp b/examples/000-CatchMain.cpp
index c8bf91e..2894d42 100644
--- a/examples/000-CatchMain.cpp
+++ b/examples/000-CatchMain.cpp
@@ -6,7 +6,7 @@
 // Let Catch provide main():
 #define CATCH_CONFIG_MAIN
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 // That's it
 
diff --git a/examples/010-TestCase.cpp b/examples/010-TestCase.cpp
index 16a212a..c00b8a8 100644
--- a/examples/010-TestCase.cpp
+++ b/examples/010-TestCase.cpp
@@ -3,7 +3,7 @@
 // Let Catch provide main():
 #define CATCH_CONFIG_MAIN
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 int Factorial( int number ) {
    return number <= 1 ? number : Factorial( number - 1 ) * number;  // fail
diff --git a/examples/020-TestCase-1.cpp b/examples/020-TestCase-1.cpp
index 0d10276..ab0249e 100644
--- a/examples/020-TestCase-1.cpp
+++ b/examples/020-TestCase-1.cpp
@@ -6,7 +6,7 @@
 // Let Catch provide main():
 #define CATCH_CONFIG_MAIN
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 TEST_CASE( "1: All test cases reside in other .cpp files (empty)", "[multi-file:1]" ) {
 }
diff --git a/examples/020-TestCase-2.cpp b/examples/020-TestCase-2.cpp
index 2cca362..08b313e 100644
--- a/examples/020-TestCase-2.cpp
+++ b/examples/020-TestCase-2.cpp
@@ -2,7 +2,7 @@
 
 // main() provided by Catch in file 020-TestCase-1.cpp.
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 int Factorial( int number ) {
    return number <= 1 ? number : Factorial( number - 1 ) * number;  // fail
diff --git a/examples/030-Asn-Require-Check.cpp b/examples/030-Asn-Require-Check.cpp
index 35f2ff7..f814a1b 100644
--- a/examples/030-Asn-Require-Check.cpp
+++ b/examples/030-Asn-Require-Check.cpp
@@ -10,7 +10,7 @@
 
 // main() provided in 000-CatchMain.cpp
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 std::string one() {
     return "1";
diff --git a/examples/100-Fix-Section.cpp b/examples/100-Fix-Section.cpp
index 8cb94bf..d0b9f2d 100644
--- a/examples/100-Fix-Section.cpp
+++ b/examples/100-Fix-Section.cpp
@@ -6,7 +6,7 @@
 
 // main() provided in 000-CatchMain.cpp
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 TEST_CASE( "vectors can be sized and resized", "[vector]" ) {
 
diff --git a/examples/110-Fix-ClassFixture.cpp b/examples/110-Fix-ClassFixture.cpp
index 06c2cf3..e42fd17 100644
--- a/examples/110-Fix-ClassFixture.cpp
+++ b/examples/110-Fix-ClassFixture.cpp
@@ -6,7 +6,7 @@
 
 // main() provided in 000-CatchMain.cpp
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 class DBConnection
 {
diff --git a/examples/120-Bdd-ScenarioGivenWhenThen.cpp b/examples/120-Bdd-ScenarioGivenWhenThen.cpp
index c45f1f2..d1b9ce5 100644
--- a/examples/120-Bdd-ScenarioGivenWhenThen.cpp
+++ b/examples/120-Bdd-ScenarioGivenWhenThen.cpp
@@ -2,7 +2,7 @@
 
 // main() provided in 000-CatchMain.cpp
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 
 SCENARIO( "vectors can be sized and resized", "[vector]" ) {
 
diff --git a/examples/200-Rpt-CatchMain.cpp b/examples/200-Rpt-CatchMain.cpp
new file mode 100644
index 0000000..b84c804
--- /dev/null
+++ b/examples/200-Rpt-CatchMain.cpp
@@ -0,0 +1,27 @@
+// 200-Rpt-CatchMain.cpp
+
+// In a Catch project with multiple files, dedicate one file to compile the
+// source code of Catch itself and reuse the resulting object file for linking.
+
+// Let Catch provide main():
+#define CATCH_CONFIG_MAIN
+
+#include <catch2/catch.hpp>
+
+#ifdef   CATCH_EXAMPLE_RPT_1
+#include CATCH_EXAMPLE_RPT_1
+#endif
+
+#ifdef   CATCH_EXAMPLE_RPT_2
+#include CATCH_EXAMPLE_RPT_2
+#endif
+
+#ifdef   CATCH_EXAMPLE_RPT_3
+#include CATCH_EXAMPLE_RPT_3
+#endif
+
+// That's it
+
+// Compile implementation of Catch for use with files that do contain tests:
+// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
+// cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
diff --git a/examples/207-Rpt-TeamCityReporter.cpp b/examples/207-Rpt-TeamCityReporter.cpp
new file mode 100644
index 0000000..d28460f
--- /dev/null
+++ b/examples/207-Rpt-TeamCityReporter.cpp
@@ -0,0 +1,171 @@
+// 207-Rpt-TeamCityReporter.cpp
+
+// Catch has built-in and external reporters:
+// Built-in:
+// - compact
+// - console
+// - junit
+// - xml
+// External:
+// - automake
+// - tap
+// - teamcity (this example)
+
+// main() and reporter code provided in 200-Rpt-CatchMain.cpp
+
+#include <catch2/catch.hpp>
+
+#ifdef _MSC_VER
+# pragma warning (disable : 4702) // Disable warning: unreachable code
+#endif
+
+TEST_CASE( "TeamCity passes unconditionally succeeding assertion", "[teamcity]" ) {
+
+    SUCCEED();
+}
+
+TEST_CASE( "TeamCity reports unconditionally failing assertion", "[teamcity]" ) {
+
+    FAIL();
+}
+
+TEST_CASE( "TeamCity reports failing check", "[teamcity]" ) {
+
+    REQUIRE( 3 == 7 );
+}
+
+TEST_CASE( "TeamCity reports failing check-false", "[teamcity]" ) {
+
+    REQUIRE_FALSE( 3 == 3 );
+}
+
+TEST_CASE( "TeamCity reports failing check-that", "[teamcity]" ) {
+
+    using namespace Catch;
+
+    REQUIRE_THAT( "hello", Contains( "world" ) );
+}
+
+TEST_CASE( "TeamCity reports unexpected exception", "[teamcity]" ) {
+
+    REQUIRE( (throw std::runtime_error("surprise!"), true) );
+}
+
+TEST_CASE( "TeamCity reports undesired exception", "[teamcity]" ) {
+
+    REQUIRE_NOTHROW( (throw std::runtime_error("surprise!"), true) );
+}
+
+TEST_CASE( "TeamCity reports missing expected exception", "[teamcity]" ) {
+
+    REQUIRE_THROWS( true );
+}
+
+TEST_CASE( "TeamCity reports missing specific expected exception", "[teamcity]" ) {
+
+    REQUIRE_THROWS_AS( throw std::bad_alloc(), std::runtime_error );
+}
+
+TEST_CASE( "TeamCity reports unexpected message in expected exception", "[teamcity]" ) {
+
+    using namespace Catch;
+
+    CHECK_THROWS_WITH( throw std::runtime_error("hello"), "world" );
+    CHECK_THROWS_WITH( throw std::runtime_error("hello"), Contains("world") );
+}
+
+struct MyException: public std::runtime_error
+{
+    MyException( char const * text )
+    : std::runtime_error( text ) {}
+    
+    ~MyException() override;
+};
+
+// prevent -Wweak-vtables:
+MyException::~MyException() = default;
+
+struct MyExceptionMatcher : Catch::MatcherBase< std::runtime_error >
+{
+    std::string m_text;
+
+    MyExceptionMatcher( char const * text )
+    : m_text( text )
+    {}
+
+    ~MyExceptionMatcher() override;
+    
+    bool match( std::runtime_error const & arg ) const override
+    { 
+        return m_text == arg.what() ; 
+    }
+    
+    std::string describe() const override 
+    { 
+        return "it's me";
+    }
+};
+
+// prevent -Wweak-vtables:
+MyExceptionMatcher::~MyExceptionMatcher() = default;
+
+TEST_CASE( "TeamCity failing check-throws-matches", "[teamcity]" ) {
+
+    CHECK_THROWS_MATCHES( throw MyException("hello"), MyException, MyExceptionMatcher("world") );
+}
+
+// [!throws] - lets Catch know that this test is likely to throw an exception even if successful. 
+// This causes the test to be excluded when running with -e or --nothrow.
+
+// No special effects for the reporter.
+
+TEST_CASE( "TeamCity throwing exception with tag [!throws]", "[teamcity][!throws]" ) {
+
+    REQUIRE_THROWS( throw std::runtime_error("unsurprisingly") );
+}
+
+// [!mayfail] - doesn't fail the test if any given assertion fails (but still reports it). This can be useful to flag a work-in-progress, or a known issue that you don't want to immediately fix but still want to track in your tests.
+
+TEST_CASE( "TeamCity failing assertion with tag [!mayfail]", "[teamcity][!mayfail] " ) {
+
+    REQUIRE( 3 == 7 );  // doesn't fail test case this time, reports: testIgnored
+    REQUIRE( 3 == 3 );
+}
+
+// [!shouldfail] - like [!mayfail] but fails the test if it passes. 
+// This can be useful if you want to be notified of accidental, or third-party, fixes.
+
+TEST_CASE( "TeamCity succeeding assertion with tag [!shouldfail]", "[teamcity][!shouldfail]" ) {
+
+    SUCCEED( "Marked [!shouldfail]" );
+}
+
+// Compile & run:
+// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -o 200-Rpt-CatchMainTeamCity.o -c 200-Rpt-CatchMain.cpp
+// - g++ -std=c++11 -Wall -I$(CATCH_ROOT) -o 207-Rpt-TeamCityReporter 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
+//
+// - cl -EHsc -I%CATCH_ROOT% -DCATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" -Fo200-Rpt-CatchMainTeamCity.obj -c 200-Rpt-CatchMain.cpp
+// - cl -EHsc -I%CATCH_ROOT% 207-Rpt-TeamCityReporter.cpp 200-Rpt-CatchMainTeamCity.o && 207-Rpt-TeamCityReporter --list-reporters
+
+// Compilation output (--list-reporters):
+// Available reporters:
+//   compact:   Reports test results on a single line, suitable for IDEs
+//   console:   Reports test results as plain lines of text
+//   junit:     Reports test results in an XML format that looks like Ant's
+//                junitreport target
+//   teamcity:  Reports test results as TeamCity service messages
+//   xml:       Reports test results as an XML document
+
+// Expected output (abbreviated and broken into shorter lines):
+//
+// prompt> 207-Rpt-TeamCityReporter.exe --reporter teamcity
+// ##teamcity[testSuiteStarted name='207-Rpt-TeamCityReporter.exe']
+// ##teamcity[testStarted name='TeamCity passes unconditionally succeeding assertion']
+// ##teamcity[testFinished name='TeamCity passes unconditionally succeeding assertion' duration='1']
+// ##teamcity[testStarted name='TeamCity reports unconditionally failing assertion']
+// ##teamcity[testFailed name='TeamCity reports unconditionally failing assertion' /
+// message='.../examples/207-Rpt-TeamCityReporter.cpp:23|n/
+// ...............................................................................|n|n/
+// .../examples/207-Rpt-TeamCityReporter.cpp:25|nexplicit failure']
+// ##teamcity[testFinished name='TeamCity reports unconditionally failing assertion' duration='3']
+// ...
diff --git a/examples/210-Evt-EventListeners.cpp b/examples/210-Evt-EventListeners.cpp
index 8ba360f..fde51c7 100644
--- a/examples/210-Evt-EventListeners.cpp
+++ b/examples/210-Evt-EventListeners.cpp
@@ -10,7 +10,7 @@
 // Let Catch provide the required interfaces:
 #define CATCH_CONFIG_EXTERNAL_INTERFACES
 
-#include "catch.hpp"
+#include <catch2/catch.hpp>
 #include <iostream>
 
 // -----------------------------------------------------------------------
@@ -187,8 +187,7 @@
 
 void print( std::ostream& os, int const level, std::string const& title, Catch::SectionInfo const& info ) {
     os << ws(level  ) << title << ":\n"
-       << ws(level+1) << "- name: "         << info.name << "\n"
-       << ws(level+1) << "- description: '" << info.description << "'\n";
+       << ws(level+1) << "- name: "         << info.name << "\n";
     print( os, level+1 , "- lineInfo", info.lineInfo );
 }
 
@@ -388,16 +387,16 @@
     REQUIRE( i == 42 );
 
     SECTION("Section 1") {
-        INFO("Section 1")
+        INFO("Section 1");
         i = 7;
         SECTION("Section 1.1") {
-            INFO("Section 1.1")
+            INFO("Section 1.1");
             REQUIRE( i == 42 );
         }
     }
 
     SECTION("Section 2") {
-        INFO("Section 2")
+        INFO("Section 2");
         REQUIRE( i == 42 );
     }
     WARN("At end of test case");
diff --git a/examples/231-Cfg-OutputStreams.cpp b/examples/231-Cfg-OutputStreams.cpp
new file mode 100644
index 0000000..efa9997
--- /dev/null
+++ b/examples/231-Cfg-OutputStreams.cpp
@@ -0,0 +1,49 @@
+// 231-Cfg-OutputStreams.cpp
+// Show how to replace the streams with a simple custom made streambuf.
+
+// Note that this reimplementation _does not_ follow `std::cerr`
+// semantic, because it buffers the output. For most uses however,
+// there is no important difference between having `std::cerr` buffered
+// or unbuffered.
+
+#define CATCH_CONFIG_NOSTDOUT
+#define CATCH_CONFIG_MAIN
+#include <catch2/catch.hpp>
+
+class out_buff : public std::stringbuf {
+    std::FILE* m_stream;
+public:
+    out_buff(std::FILE* stream) :m_stream(stream) {}
+    ~out_buff() { pubsync(); }
+    int sync() {
+        int ret = 0;
+        for (unsigned char c : str()) {
+            if (putc(c, m_stream) == EOF) {
+                ret = -1;
+                break;
+            }
+        }
+        // Reset the buffer to avoid printing it multiple times
+        str("");
+        return ret;
+    }
+};
+
+namespace Catch {
+    std::ostream& cout() {
+        static std::ostream ret(new out_buff(stdout));
+        return ret;
+    }
+    std::ostream& clog() {
+        static std::ostream ret(new out_buff(stderr));
+        return ret;
+    }
+    std::ostream& cerr() {
+        return clog();
+    }
+}
+
+
+TEST_CASE("This binary uses putc to write out output", "[compilation-only]") {
+    SUCCEED("Nothing to test.");
+}
diff --git a/examples/300-Gen-OwnGenerator.cpp b/examples/300-Gen-OwnGenerator.cpp
new file mode 100644
index 0000000..c8b6a65
--- /dev/null
+++ b/examples/300-Gen-OwnGenerator.cpp
@@ -0,0 +1,59 @@
+// 300-Gen-OwnGenerator.cpp
+// Shows how to define a custom generator.
+
+// Specifically we will implement a random number generator for integers
+// It will have infinite capacity and settable lower/upper bound
+
+#include <catch2/catch.hpp>
+
+#include <random>
+
+// This class shows how to implement a simple generator for Catch tests
+class RandomIntGenerator : public Catch::Generators::IGenerator<int> {
+    std::minstd_rand m_rand;
+    std::uniform_int_distribution<> m_dist;
+    int current_number;
+public:
+
+    RandomIntGenerator(int low, int high):
+        m_rand(std::random_device{}()),
+        m_dist(low, high)
+    {
+        static_cast<void>(next());
+    }
+
+    int const& get() const override;
+    bool next() override {
+        current_number = m_dist(m_rand);
+        return true;
+    }
+};
+
+// Avoids -Wweak-vtables
+int const& RandomIntGenerator::get() const {
+    return current_number;
+}
+
+// This helper function provides a nicer UX when instantiating the generator
+// Notice that it returns an instance of GeneratorWrapper<int>, which
+// is a value-wrapper around std::unique_ptr<IGenerator<int>>.
+Catch::Generators::GeneratorWrapper<int> random(int low, int high) {
+    return Catch::Generators::GeneratorWrapper<int>(std::unique_ptr<Catch::Generators::IGenerator<int>>(new RandomIntGenerator(low, high)));
+}
+
+// The two sections in this test case are equivalent, but the first one
+// is much more readable/nicer to use
+TEST_CASE("Generating random ints", "[example][generator]") {
+    SECTION("Nice UX") {
+        auto i = GENERATE(take(100, random(-100, 100)));
+        REQUIRE(i >= -100);
+        REQUIRE(i <= 100);
+    }
+    SECTION("Creating the random generator directly") {
+        auto i = GENERATE(take(100, GeneratorWrapper<int>(std::unique_ptr<IGenerator<int>>(new RandomIntGenerator(-100, 100)))));
+        REQUIRE(i >= -100);
+        REQUIRE(i <= 100);
+    }
+}
+
+// Compiling and running this file will result in 400 successful assertions
diff --git a/examples/301-Gen-MapTypeConversion.cpp b/examples/301-Gen-MapTypeConversion.cpp
new file mode 100644
index 0000000..b6377e9
--- /dev/null
+++ b/examples/301-Gen-MapTypeConversion.cpp
@@ -0,0 +1,54 @@
+// 301-Gen-MapTypeConversion.cpp
+// Shows how to use map to modify generator's return type.
+
+// TODO
+
+#include <catch2/catch.hpp>
+
+#include <string>
+#include <sstream>
+
+// Returns a line from a stream. You could have it e.g. read lines from
+// a file, but to avoid problems with paths in examples, we will use
+// a fixed stringstream.
+class LineGenerator : public Catch::Generators::IGenerator<std::string> {
+    std::string m_line;
+    std::stringstream m_stream;
+public:
+    LineGenerator() {
+        m_stream.str("1\n2\n3\n4\n");
+        if (!next()) {
+            throw Catch::GeneratorException("Couldn't read a single line");
+        }
+    }
+
+    std::string const& get() const override {
+        return m_line;
+    }
+    
+    bool next() override {
+        return !!std::getline(m_stream, m_line);
+    }
+};
+
+// This helper function provides a nicer UX when instantiating the generator
+// Notice that it returns an instance of GeneratorWrapper<std::string>, which
+// is a value-wrapper around std::unique_ptr<IGenerator<std::string>>.
+Catch::Generators::GeneratorWrapper<std::string> lines(std::string /* ignored for example */) {
+    return Catch::Generators::GeneratorWrapper<std::string>(
+        std::unique_ptr<Catch::Generators::IGenerator<std::string>>(
+            new LineGenerator()
+        )
+    );
+}
+
+
+
+TEST_CASE("filter can convert types inside the generator expression", "[example][generator]") {
+    auto num = GENERATE(map<int>([](std::string const& line) { return std::stoi(line); },
+                                 lines("fake-file")));
+                                 
+    REQUIRE(num > 0);
+}
+
+// Compiling and running this file will result in 4 successful assertions
diff --git a/examples/310-Gen-VariablesInGenerators.cpp b/examples/310-Gen-VariablesInGenerators.cpp
new file mode 100644
index 0000000..96840bb
--- /dev/null
+++ b/examples/310-Gen-VariablesInGenerators.cpp
@@ -0,0 +1,72 @@
+// 310-Gen-VariablesInGenerator.cpp
+// Shows how to use variables when creating generators.
+
+// Note that using variables inside generators is dangerous and should
+// be done only if you know what you are doing, because the generators
+// _WILL_ outlive the variables -- thus they should be either captured
+// by value directly, or copied by the generators during construction.
+
+#include <catch2/catch.hpp>
+
+#include <random>
+
+// Lets start by implementing a parametrizable double generator
+class RandomDoubleGenerator : public Catch::Generators::IGenerator<double> {
+    std::minstd_rand m_rand;
+    std::uniform_real_distribution<> m_dist;
+    double current_number;
+public:
+
+    RandomDoubleGenerator(double low, double high):
+        m_rand(std::random_device{}()),
+        m_dist(low, high)
+    {
+        static_cast<void>(next());
+    }
+
+    double const& get() const override;
+    bool next() override {
+        current_number = m_dist(m_rand);
+        return true;
+    }
+};
+
+// Avoids -Wweak-vtables
+double const& RandomDoubleGenerator::get() const {
+    return current_number;
+}
+
+
+// Also provide a nice shortcut for creating the generator
+Catch::Generators::GeneratorWrapper<double> random(double low, double high) {
+    return Catch::Generators::GeneratorWrapper<double>(std::unique_ptr<Catch::Generators::IGenerator<double>>(new RandomDoubleGenerator(low, high)));
+}
+
+
+TEST_CASE("Generate random doubles across different ranges",
+          "[generator][example][advanced]") {
+    // Workaround for old libstdc++
+    using record = std::tuple<double, double>;
+    // Set up 3 ranges to generate numbers from
+    auto r = GENERATE(table<double, double>({
+        record{3, 4},
+        record{-4, -3},
+        record{10, 1000}
+    }));
+
+    // This will not compile (intentionally), because it accesses a variable
+    // auto number = GENERATE(take(50, random(r.first, r.second)));
+    
+    // We have to manually register the generators instead
+    // Notice that we are using value capture in the lambda, to avoid lifetime issues
+    auto number = Catch::Generators::generate( CATCH_INTERNAL_LINEINFO,
+        [=]{
+            using namespace Catch::Generators;
+            return makeGenerators(take(50, random(std::get<0>(r), std::get<1>(r))));
+        }
+    );
+    REQUIRE(std::abs(number) > 0);
+}
+
+// Compiling and running this file will result in 150 successful assertions
+
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index 7270e93..dff5c74 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -8,15 +8,19 @@
 
 project( CatchExamples CXX )
 
+message( STATUS "Examples included" )
+
 # define folders used:
 
 set( EXAMPLES_DIR ${CATCH_DIR}/examples )
 set( HEADER_DIR   ${CATCH_DIR}/single_include )
+set( REPORTER_HEADER_DIR ${CATCH_DIR}/include/reporters )
 
 # single-file sources:
 
 set( SOURCES_SINGLE_FILE
     010-TestCase.cpp
+    231-Cfg-OutputStreams.cpp
 )
 
 # multiple-file modules:
@@ -40,6 +44,29 @@
     110-Fix-ClassFixture.cpp
     120-Bdd-ScenarioGivenWhenThen.cpp
     210-Evt-EventListeners.cpp
+    300-Gen-OwnGenerator.cpp
+    301-Gen-MapTypeConversion.cpp
+    310-Gen-VariablesInGenerators.cpp
+)
+
+# main-s for reporter-specific test sources:
+
+set( SOURCES_REPORTERS_MAIN
+    200-Rpt-CatchMain.cpp
+)
+
+string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN 200-Rpt-CatchMain.cpp )
+
+set( NAMES_REPORTERS TeamCity )
+
+foreach( reporter ${NAMES_REPORTERS} )
+    list( APPEND SOURCES_SPECIFIC_REPORTERS_MAIN ${BASENAMES_REPORTERS_MAIN}${reporter}.cpp )
+endforeach()
+
+# sources to combine with 200-Rpt-CatchMain{Reporter}.cpp:
+
+set( SOURCES_REPORTERS_TESTS
+    207-Rpt-TeamCityReporter.cpp
 )
 
 # check if all sources are listed, warn if not:
@@ -49,6 +76,8 @@
     ${SOURCES_SINGLE_FILE}
     ${SOURCES_IDIOMATIC_MAIN}
     ${SOURCES_IDIOMATIC_TESTS}
+    ${SOURCES_REPORTERS_MAIN}
+    ${SOURCES_REPORTERS_TESTS}
 )
 
 foreach( name ${SOURCES_ALL} )
@@ -61,29 +90,55 @@
 
 string( REPLACE ".cpp" "" BASENAMES_SINGLE_FILE     "${SOURCES_SINGLE_FILE}" )
 string( REPLACE ".cpp" "" BASENAMES_IDIOMATIC_TESTS "${SOURCES_IDIOMATIC_TESTS}" )
+string( REPLACE ".cpp" "" BASENAMES_REPORTERS_TESTS "${SOURCES_REPORTERS_TESTS}" )
+string( REPLACE ".cpp" "" BASENAMES_REPORTERS_MAIN  "${SOURCES_REPORTERS_MAIN}" )
 
 set( TARGETS_SINGLE_FILE     ${BASENAMES_SINGLE_FILE} )
 set( TARGETS_IDIOMATIC_TESTS ${BASENAMES_IDIOMATIC_TESTS} )
-set( TARGETS_ALL             ${TARGETS_SINGLE_FILE} ${TARGETS_IDIOMATIC_TESTS} 020-TestCase CatchMain )
+set( TARGETS_REPORTERS_TESTS ${BASENAMES_REPORTERS_TESTS} )
+set( TARGETS_REPORTERS_MAIN  ${BASENAMES_REPORTERS_MAIN} )
+
+set( TARGETS_ALL
+    ${TARGETS_SINGLE_FILE}
+    020-TestCase
+    ${TARGETS_IDIOMATIC_TESTS} CatchMain
+    ${TARGETS_REPORTERS_TESTS} CatchMainTeamCity
+)
 
 # define program targets:
 
-add_library( CatchMain OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch.hpp )
+add_library( CatchMain         OBJECT ${EXAMPLES_DIR}/${SOURCES_IDIOMATIC_MAIN} ${HEADER_DIR}/catch2/catch.hpp )
+#add_library( CatchMainAutomake OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
+#add_library( CatchMainTap      OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
+add_library( CatchMainTeamCity OBJECT ${EXAMPLES_DIR}/200-Rpt-CatchMain.cpp ${HEADER_DIR}/catch2/catch.hpp )
 
-add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch.hpp )
+#target_compile_definitions( CatchMainAutomake PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_automake.hpp\" )
+#target_compile_definitions( CatchMainTap      PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_tap.hpp\" )
+target_compile_definitions( CatchMainTeamCity PRIVATE CATCH_EXAMPLE_RPT_1=\"include/reporters/catch_reporter_teamcity.hpp\" )
 
 foreach( name ${TARGETS_SINGLE_FILE} )
-    add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch.hpp )
+    add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp ${HEADER_DIR}/catch2/catch.hpp )
 endforeach()
 
 foreach( name ${TARGETS_IDIOMATIC_TESTS} )
-    add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch.hpp )
+    add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
 endforeach()
 
+add_executable( 020-TestCase ${EXAMPLES_DIR}/020-TestCase-1.cpp ${EXAMPLES_DIR}/020-TestCase-2.cpp ${HEADER_DIR}/catch2/catch.hpp )
+
+#add_executable( 207-Rpt-AutomakeReporter ${EXAMPLES_DIR}/207-Rpt-AutomakeReporter.cpp $<TARGET_OBJECTS:CatchMainAutomake> ${HEADER_DIR}/catch2/catch.hpp )
+#add_executable( 207-Rpt-TapReporter      ${EXAMPLES_DIR}/207-Rpt-TapReporter.cpp      $<TARGET_OBJECTS:CatchMainTap>      ${HEADER_DIR}/catch2/catch.hpp )
+add_executable( 207-Rpt-TeamCityReporter ${EXAMPLES_DIR}/207-Rpt-TeamCityReporter.cpp $<TARGET_OBJECTS:CatchMainTeamCity> ${HEADER_DIR}/catch2/catch.hpp )
+
+#foreach( name ${TARGETS_REPORTERS_TESTS} )
+#    add_executable( ${name} ${EXAMPLES_DIR}/${name}.cpp $<TARGET_OBJECTS:CatchMain> ${HEADER_DIR}/catch2/catch.hpp )
+#endforeach()
+
 foreach( name ${TARGETS_ALL} )
-    target_include_directories( ${name} PRIVATE ${HEADER_DIR} )
+    target_include_directories( ${name} PRIVATE ${HEADER_DIR} ${CATCH_DIR} )
 
     set_property(TARGET ${name} PROPERTY CXX_STANDARD 11)
+    set_property(TARGET ${name} PROPERTY CXX_EXTENSIONS OFF)
 
     # Add desired warnings
     if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|AppleClang|GNU" )
@@ -98,3 +153,4 @@
         target_compile_options( ${name}  PRIVATE /W4 /w44265 /WX )
     endif()
 endforeach()
+
diff --git a/include/catch.hpp b/include/catch.hpp
index 0a4711b..e15588f 100644
--- a/include/catch.hpp
+++ b/include/catch.hpp
@@ -10,8 +10,8 @@
 #define TWOBLUECUBES_CATCH_HPP_INCLUDED
 
 #define CATCH_VERSION_MAJOR 2
-#define CATCH_VERSION_MINOR 1
-#define CATCH_VERSION_PATCH 1
+#define CATCH_VERSION_MINOR 7
+#define CATCH_VERSION_PATCH 0
 
 #ifdef __clang__
 #    pragma clang system_header
@@ -33,7 +33,9 @@
 #  if defined(CATCH_CONFIG_DISABLE_MATCHERS)
 #    undef CATCH_CONFIG_DISABLE_MATCHERS
 #  endif
-#  define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#  if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER)
+#    define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#  endif
 #endif
 
 #if !defined(CATCH_CONFIG_IMPL_ONLY)
@@ -60,6 +62,9 @@
 #ifndef CATCH_CONFIG_DISABLE_MATCHERS
 #include "internal/catch_capture_matchers.h"
 #endif
+#include "internal/catch_generators.hpp"
+#include "internal/catch_generators_generic.hpp"
+#include "internal/catch_generators_specific.hpp"
 
 // These files are included here so the single_include script doesn't put them
 // in the conditionally compiled sections
@@ -98,7 +103,7 @@
 #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
 #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
 
-#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, "", __VA_ARGS__ )
+#define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
 #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -112,7 +117,7 @@
 #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
 
-#define CATCH_CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, "", __VA_ARGS__ )
+#define CATCH_CHECK_THROWS( ... )  INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
 #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
 #if !defined(CATCH_CONFIG_DISABLE_MATCHERS)
@@ -128,27 +133,51 @@
 
 #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
 #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
-#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( "CATCH_CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
+#define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE",__VA_ARGS__ )
 
 #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( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
 #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
 #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
 #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 
 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
 
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#endif
+
+
+#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+#define CATCH_STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__ ,      #__VA_ARGS__ );     CATCH_SUCCEED( #__VA_ARGS__ )
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
+#else
+#define CATCH_STATIC_REQUIRE( ... )       CATCH_REQUIRE( __VA_ARGS__ )
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
+#endif
+
+
 // "BDD-style" convenience wrappers
 #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
-#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 )
+#define CATCH_GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( "    Given: " << desc )
+#define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define CATCH_WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     When: " << desc )
+#define CATCH_AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define CATCH_THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     Then: " << desc )
+#define CATCH_AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( "      And: " << desc )
 
 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
 #else
@@ -186,19 +215,42 @@
 #endif // CATCH_CONFIG_DISABLE_MATCHERS
 
 #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
+#define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
 #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
-#define CAPTURE( msg ) INTERNAL_CATCH_INFO( "CAPTURE", #msg " := " << ::Catch::Detail::stringify(msg) )
+#define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE",__VA_ARGS__ )
 
 #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( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
 #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+#define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
 #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
 #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE()
 
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
+#endif
+
+
+#if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
+#define STATIC_REQUIRE( ... )       static_assert(   __VA_ARGS__,  #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
+#define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
+#else
+#define STATIC_REQUIRE( ... )       REQUIRE( __VA_ARGS__ )
+#define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
+#endif
+
 #endif
 
 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
@@ -207,15 +259,17 @@
 #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
 
-#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 )
+#define GIVEN( desc )     INTERNAL_CATCH_DYNAMIC_SECTION( "    Given: " << desc )
+#define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
+#define WHEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     When: " << desc )
+#define AND_WHEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
+#define THEN( desc )      INTERNAL_CATCH_DYNAMIC_SECTION( "     Then: " << desc )
+#define AND_THEN( desc )  INTERNAL_CATCH_DYNAMIC_SECTION( "      And: " << desc )
 
 using Catch::Detail::Approx;
 
-#else
+#else // CATCH_CONFIG_DISABLE
+
 //////
 // If this config identifier is defined then all CATCH macros are prefixed with CATCH_
 #ifdef CATCH_CONFIG_PREFIX_ALL
@@ -260,21 +314,38 @@
 #define CATCH_METHOD_AS_TEST_CASE( method, ... )
 #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
 #define CATCH_SECTION( ... )
+#define CATCH_DYNAMIC_SECTION( ... )
 #define CATCH_FAIL( ... ) (void)(0)
 #define CATCH_FAIL_CHECK( ... ) (void)(0)
 #define CATCH_SUCCEED( ... ) (void)(0)
 
 #define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
 
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
+#define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
 // "BDD-style" convenience wrappers
 #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
 #define CATCH_GIVEN( desc )
+#define CATCH_AND_GIVEN( desc )
 #define CATCH_WHEN( desc )
 #define CATCH_AND_WHEN( desc )
 #define CATCH_THEN( desc )
 #define CATCH_AND_THEN( desc )
 
+#define CATCH_STATIC_REQUIRE( ... )       (void)(0)
+#define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
+
 // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
 #else
 
@@ -319,11 +390,27 @@
 #define METHOD_AS_TEST_CASE( method, ... )
 #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
 #define SECTION( ... )
+#define DYNAMIC_SECTION( ... )
 #define FAIL( ... ) (void)(0)
 #define FAIL_CHECK( ... ) (void)(0)
 #define SUCCEED( ... ) (void)(0)
 #define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ))
 
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#else
+#define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) ) )
+#define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), className ) )
+#define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
+#define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
+#endif
+
+#define STATIC_REQUIRE( ... )       (void)(0)
+#define STATIC_REQUIRE_FALSE( ... ) (void)(0)
+
 #endif
 
 #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
@@ -333,6 +420,7 @@
 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className )
 
 #define GIVEN( desc )
+#define AND_GIVEN( desc )
 #define WHEN( desc )
 #define AND_WHEN( desc )
 #define THEN( desc )
diff --git a/include/catch_with_main.cpp b/include/catch_with_main.cpp
new file mode 120000
index 0000000..273da6b
--- /dev/null
+++ b/include/catch_with_main.cpp
@@ -0,0 +1 @@
+catch_with_main.hpp
\ No newline at end of file
diff --git a/include/external/clara.hpp b/include/external/clara.hpp
index 31dea24..20c6da7 100644
--- a/include/external/clara.hpp
+++ b/include/external/clara.hpp
@@ -5,7 +5,7 @@
 //
 // See https://github.com/philsquared/Clara for more details
 
-// Clara v1.1.1
+// Clara v1.1.5
 
 #ifndef CATCH_CLARA_HPP_INCLUDED
 #define CATCH_CLARA_HPP_INCLUDED
@@ -18,14 +18,24 @@
 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH CATCH_CLARA_CONFIG_CONSOLE_WIDTH
 #endif
 
+#ifndef CLARA_CONFIG_OPTIONAL_TYPE
+#ifdef __has_include
+#if __has_include(<optional>) && __cplusplus >= 201703L
+#include <optional>
+#define CLARA_CONFIG_OPTIONAL_TYPE std::optional
+#endif
+#endif
+#endif
+
+
 // ----------- #included from clara_textflow.hpp -----------
 
 // TextFlowCpp
 //
 // A single-header library for wrapping and laying out basic text, by Phil Nash
 //
-// This work is licensed under the BSD 2-Clause license.
-// See the accompanying LICENSE file, or the one at https://opensource.org/licenses/BSD-2-Clause
+// Distributed under the Boost Software License, Version 1.0. (See accompanying
+// file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 //
 // This project is hosted at https://github.com/philsquared/textflowcpp
 
@@ -41,324 +51,327 @@
 #define CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH 80
 #endif
 
-#if CATCH_CONFIG_USE_EXCEPTIONS == 0
-// std::cerr + std::terminate instead of 'throw'
-#include <iostream>
-#include <exception>
-#endif
 
+namespace Catch {
+namespace clara {
+namespace TextFlow {
 
-namespace Catch { namespace clara { namespace TextFlow {
+inline auto isWhitespace(char c) -> bool {
+	static std::string chars = " \t\n\r";
+	return chars.find(c) != std::string::npos;
+}
+inline auto isBreakableBefore(char c) -> bool {
+	static std::string chars = "[({<|";
+	return chars.find(c) != std::string::npos;
+}
+inline auto isBreakableAfter(char c) -> bool {
+	static std::string chars = "])}>.,:;*+-=&/\\";
+	return chars.find(c) != std::string::npos;
+}
 
-    inline auto isWhitespace( char c ) -> bool {
-        static std::string chars = " \t\n\r";
-        return chars.find( c ) != std::string::npos;
-    }
-    inline auto isBreakableBefore( char c ) -> bool {
-        static std::string chars = "[({<|";
-        return chars.find( c ) != std::string::npos;
-    }
-    inline auto isBreakableAfter( char c ) -> bool {
-        static std::string chars = "])}>.,:;*+-=&/\\";
-        return chars.find( c ) != std::string::npos;
-    }
+class Columns;
 
-    class Columns;
+class Column {
+	std::vector<std::string> m_strings;
+	size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
+	size_t m_indent = 0;
+	size_t m_initialIndent = std::string::npos;
 
-    class Column {
-        std::vector<std::string> m_strings;
-        size_t m_width = CATCH_CLARA_TEXTFLOW_CONFIG_CONSOLE_WIDTH;
-        size_t m_indent = 0;
-        size_t m_initialIndent = std::string::npos;
+public:
+	class iterator {
+		friend Column;
 
-    public:
-        class iterator {
-            friend Column;
+		Column const& m_column;
+		size_t m_stringIndex = 0;
+		size_t m_pos = 0;
 
-            Column const& m_column;
-            size_t m_stringIndex = 0;
-            size_t m_pos = 0;
+		size_t m_len = 0;
+		size_t m_end = 0;
+		bool m_suffix = false;
 
-            size_t m_len = 0;
-            size_t m_end = 0;
-            bool m_suffix = false;
+		iterator(Column const& column, size_t stringIndex)
+			: m_column(column),
+			m_stringIndex(stringIndex) {}
 
-            iterator( Column const& column, size_t stringIndex )
-            :   m_column( column ),
-                m_stringIndex( stringIndex )
-            {}
+		auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
 
-            auto line() const -> std::string const& { return m_column.m_strings[m_stringIndex]; }
+		auto isBoundary(size_t at) const -> bool {
+			assert(at > 0);
+			assert(at <= line().size());
 
-            auto isBoundary( size_t at ) const -> bool {
-                assert( at > 0 );
-                assert( at <= line().size() );
+			return at == line().size() ||
+				(isWhitespace(line()[at]) && !isWhitespace(line()[at - 1])) ||
+				isBreakableBefore(line()[at]) ||
+				isBreakableAfter(line()[at - 1]);
+		}
 
-                return at == line().size() ||
-                       ( isWhitespace( line()[at] ) && !isWhitespace( line()[at-1] ) ) ||
-                       isBreakableBefore( line()[at] ) ||
-                       isBreakableAfter( line()[at-1] );
-            }
+		void calcLength() {
+			assert(m_stringIndex < m_column.m_strings.size());
 
-            void calcLength() {
-                assert( m_stringIndex < m_column.m_strings.size() );
+			m_suffix = false;
+			auto width = m_column.m_width - indent();
+			m_end = m_pos;
+			while (m_end < line().size() && line()[m_end] != '\n')
+				++m_end;
 
-                m_suffix = false;
-                auto width = m_column.m_width-indent();
-                m_end = m_pos;
-                while( m_end < line().size() && line()[m_end] != '\n' )
-                    ++m_end;
+			if (m_end < m_pos + width) {
+				m_len = m_end - m_pos;
+			} else {
+				size_t len = width;
+				while (len > 0 && !isBoundary(m_pos + len))
+					--len;
+				while (len > 0 && isWhitespace(line()[m_pos + len - 1]))
+					--len;
 
-                if( m_end < m_pos + width ) {
-                    m_len = m_end - m_pos;
-                }
-                else {
-                    size_t len = width;
-                    while (len > 0 && !isBoundary(m_pos + len))
-                        --len;
-                    while (len > 0 && isWhitespace( line()[m_pos + len - 1] ))
-                        --len;
+				if (len > 0) {
+					m_len = len;
+				} else {
+					m_suffix = true;
+					m_len = width - 1;
+				}
+			}
+		}
 
-                    if (len > 0) {
-                        m_len = len;
-                    } else {
-                        m_suffix = true;
-                        m_len = width - 1;
-                    }
-                }
-            }
+		auto indent() const -> size_t {
+			auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
+			return initial == std::string::npos ? m_column.m_indent : initial;
+		}
 
-            auto indent() const -> size_t {
-                auto initial = m_pos == 0 && m_stringIndex == 0 ? m_column.m_initialIndent : std::string::npos;
-                return initial == std::string::npos ? m_column.m_indent : initial;
-            }
+		auto addIndentAndSuffix(std::string const &plain) const -> std::string {
+			return std::string(indent(), ' ') + (m_suffix ? plain + "-" : plain);
+		}
 
-            auto addIndentAndSuffix(std::string const &plain) const -> std::string {
-                return std::string( indent(), ' ' ) + (m_suffix ? plain + "-" : plain);
-            }
+	public:
+		using difference_type = std::ptrdiff_t;
+		using value_type = std::string;
+		using pointer = value_type * ;
+		using reference = value_type & ;
+		using iterator_category = std::forward_iterator_tag;
 
-        public:
-            explicit iterator( Column const& column ) : m_column( column ) {
-                assert( m_column.m_width > m_column.m_indent );
-                assert( m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent );
-                calcLength();
-                if( m_len == 0 )
-                    m_stringIndex++; // Empty string
-            }
+		explicit iterator(Column const& column) : m_column(column) {
+			assert(m_column.m_width > m_column.m_indent);
+			assert(m_column.m_initialIndent == std::string::npos || m_column.m_width > m_column.m_initialIndent);
+			calcLength();
+			if (m_len == 0)
+				m_stringIndex++; // Empty string
+		}
 
-            auto operator *() const -> std::string {
-                assert( m_stringIndex < m_column.m_strings.size() );
-                assert( m_pos <= m_end );
-                if( m_pos + m_column.m_width < m_end )
-                    return addIndentAndSuffix(line().substr(m_pos, m_len));
-                else
-                    return addIndentAndSuffix(line().substr(m_pos, m_end - m_pos));
-            }
+		auto operator *() const -> std::string {
+			assert(m_stringIndex < m_column.m_strings.size());
+			assert(m_pos <= m_end);
+			return addIndentAndSuffix(line().substr(m_pos, m_len));
+		}
 
-            auto operator ++() -> iterator& {
-                m_pos += m_len;
-                if( m_pos < line().size() && line()[m_pos] == '\n' )
-                    m_pos += 1;
-                else
-                    while( m_pos < line().size() && isWhitespace( line()[m_pos] ) )
-                        ++m_pos;
+		auto operator ++() -> iterator& {
+			m_pos += m_len;
+			if (m_pos < line().size() && line()[m_pos] == '\n')
+				m_pos += 1;
+			else
+				while (m_pos < line().size() && isWhitespace(line()[m_pos]))
+					++m_pos;
 
-                if( m_pos == line().size() ) {
-                    m_pos = 0;
-                    ++m_stringIndex;
-                }
-                if( m_stringIndex < m_column.m_strings.size() )
-                    calcLength();
-                return *this;
-            }
-            auto operator ++(int) -> iterator {
-                iterator prev( *this );
-                operator++();
-                return prev;
-            }
+			if (m_pos == line().size()) {
+				m_pos = 0;
+				++m_stringIndex;
+			}
+			if (m_stringIndex < m_column.m_strings.size())
+				calcLength();
+			return *this;
+		}
+		auto operator ++(int) -> iterator {
+			iterator prev(*this);
+			operator++();
+			return prev;
+		}
 
-            auto operator ==( iterator const& other ) const -> bool {
-                return
-                    m_pos == other.m_pos &&
-                    m_stringIndex == other.m_stringIndex &&
-                    &m_column == &other.m_column;
-            }
-            auto operator !=( iterator const& other ) const -> bool {
-                return !operator==( other );
-            }
-        };
-        using const_iterator = iterator;
+		auto operator ==(iterator const& other) const -> bool {
+			return
+				m_pos == other.m_pos &&
+				m_stringIndex == other.m_stringIndex &&
+				&m_column == &other.m_column;
+		}
+		auto operator !=(iterator const& other) const -> bool {
+			return !operator==(other);
+		}
+	};
+	using const_iterator = iterator;
 
-        explicit Column( std::string const& text ) { m_strings.push_back( text ); }
+	explicit Column(std::string const& text) { m_strings.push_back(text); }
 
-        auto width( size_t newWidth ) -> Column& {
-            assert( newWidth > 0 );
-            m_width = newWidth;
-            return *this;
-        }
-        auto indent( size_t newIndent ) -> Column& {
-            m_indent = newIndent;
-            return *this;
-        }
-        auto initialIndent( size_t newIndent ) -> Column& {
-            m_initialIndent = newIndent;
-            return *this;
-        }
+	auto width(size_t newWidth) -> Column& {
+		assert(newWidth > 0);
+		m_width = newWidth;
+		return *this;
+	}
+	auto indent(size_t newIndent) -> Column& {
+		m_indent = newIndent;
+		return *this;
+	}
+	auto initialIndent(size_t newIndent) -> Column& {
+		m_initialIndent = newIndent;
+		return *this;
+	}
 
-        auto width() const -> size_t { return m_width; }
-        auto begin() const -> iterator { return iterator( *this ); }
-        auto end() const -> iterator { return { *this, m_strings.size() }; }
+	auto width() const -> size_t { return m_width; }
+	auto begin() const -> iterator { return iterator(*this); }
+	auto end() const -> iterator { return { *this, m_strings.size() }; }
 
-        inline friend std::ostream& operator << ( std::ostream& os, Column const& col ) {
-            bool first = true;
-            for( auto line : col ) {
-                if( first )
-                    first = false;
-                else
-                    os << "\n";
-                os <<  line;
-            }
-            return os;
-        }
+	inline friend std::ostream& operator << (std::ostream& os, Column const& col) {
+		bool first = true;
+		for (auto line : col) {
+			if (first)
+				first = false;
+			else
+				os << "\n";
+			os << line;
+		}
+		return os;
+	}
 
-        auto operator + ( Column const& other ) -> Columns;
+	auto operator + (Column const& other)->Columns;
 
-        auto toString() const -> std::string {
-            std::ostringstream oss;
-            oss << *this;
-            return oss.str();
-        }
-    };
+	auto toString() const -> std::string {
+		std::ostringstream oss;
+		oss << *this;
+		return oss.str();
+	}
+};
 
-    class Spacer : public Column {
+class Spacer : public Column {
 
-    public:
-        explicit Spacer( size_t spaceWidth ) : Column( "" ) {
-            width( spaceWidth );
-        }
-    };
+public:
+	explicit Spacer(size_t spaceWidth) : Column("") {
+		width(spaceWidth);
+	}
+};
 
-    class Columns {
-        std::vector<Column> m_columns;
+class Columns {
+	std::vector<Column> m_columns;
 
-    public:
+public:
 
-        class iterator {
-            friend Columns;
-            struct EndTag {};
+	class iterator {
+		friend Columns;
+		struct EndTag {};
 
-            std::vector<Column> const& m_columns;
-            std::vector<Column::iterator> m_iterators;
-            size_t m_activeIterators;
+		std::vector<Column> const& m_columns;
+		std::vector<Column::iterator> m_iterators;
+		size_t m_activeIterators;
 
-            iterator( Columns const& columns, EndTag )
-            :   m_columns( columns.m_columns ),
-                m_activeIterators( 0 )
-            {
-                m_iterators.reserve( m_columns.size() );
+		iterator(Columns const& columns, EndTag)
+			: m_columns(columns.m_columns),
+			m_activeIterators(0) {
+			m_iterators.reserve(m_columns.size());
 
-                for( auto const& col : m_columns )
-                    m_iterators.push_back( col.end() );
-            }
+			for (auto const& col : m_columns)
+				m_iterators.push_back(col.end());
+		}
 
-        public:
-            explicit iterator( Columns const& columns )
-            :   m_columns( columns.m_columns ),
-                m_activeIterators( m_columns.size() )
-            {
-                m_iterators.reserve( m_columns.size() );
+	public:
+		using difference_type = std::ptrdiff_t;
+		using value_type = std::string;
+		using pointer = value_type * ;
+		using reference = value_type & ;
+		using iterator_category = std::forward_iterator_tag;
 
-                for( auto const& col : m_columns )
-                    m_iterators.push_back( col.begin() );
-            }
+		explicit iterator(Columns const& columns)
+			: m_columns(columns.m_columns),
+			m_activeIterators(m_columns.size()) {
+			m_iterators.reserve(m_columns.size());
 
-            auto operator ==( iterator const& other ) const -> bool {
-                return m_iterators == other.m_iterators;
-            }
-            auto operator !=( iterator const& other ) const -> bool {
-                return m_iterators != other.m_iterators;
-            }
-            auto operator *() const -> std::string {
-                std::string row, padding;
+			for (auto const& col : m_columns)
+				m_iterators.push_back(col.begin());
+		}
 
-                for( size_t i = 0; i < m_columns.size(); ++i ) {
-                    auto width = m_columns[i].width();
-                    if( m_iterators[i] != m_columns[i].end() ) {
-                        std::string col = *m_iterators[i];
-                        row += padding + col;
-                        if( col.size() < width )
-                            padding = std::string( width - col.size(), ' ' );
-                        else
-                            padding = "";
-                    }
-                    else {
-                        padding += std::string( width, ' ' );
-                    }
-                }
-                return row;
-            }
-            auto operator ++() -> iterator& {
-                for( size_t i = 0; i < m_columns.size(); ++i ) {
-                    if (m_iterators[i] != m_columns[i].end())
-                        ++m_iterators[i];
-                }
-                return *this;
-            }
-            auto operator ++(int) -> iterator {
-                iterator prev( *this );
-                operator++();
-                return prev;
-            }
-        };
-        using const_iterator = iterator;
+		auto operator ==(iterator const& other) const -> bool {
+			return m_iterators == other.m_iterators;
+		}
+		auto operator !=(iterator const& other) const -> bool {
+			return m_iterators != other.m_iterators;
+		}
+		auto operator *() const -> std::string {
+			std::string row, padding;
 
-        auto begin() const -> iterator { return iterator( *this ); }
-        auto end() const -> iterator { return { *this, iterator::EndTag() }; }
+			for (size_t i = 0; i < m_columns.size(); ++i) {
+				auto width = m_columns[i].width();
+				if (m_iterators[i] != m_columns[i].end()) {
+					std::string col = *m_iterators[i];
+					row += padding + col;
+					if (col.size() < width)
+						padding = std::string(width - col.size(), ' ');
+					else
+						padding = "";
+				} else {
+					padding += std::string(width, ' ');
+				}
+			}
+			return row;
+		}
+		auto operator ++() -> iterator& {
+			for (size_t i = 0; i < m_columns.size(); ++i) {
+				if (m_iterators[i] != m_columns[i].end())
+					++m_iterators[i];
+			}
+			return *this;
+		}
+		auto operator ++(int) -> iterator {
+			iterator prev(*this);
+			operator++();
+			return prev;
+		}
+	};
+	using const_iterator = iterator;
 
-        auto operator += ( Column const& col ) -> Columns& {
-            m_columns.push_back( col );
-            return *this;
-        }
-        auto operator + ( Column const& col ) -> Columns {
-            Columns combined = *this;
-            combined += col;
-            return combined;
-        }
+	auto begin() const -> iterator { return iterator(*this); }
+	auto end() const -> iterator { return { *this, iterator::EndTag() }; }
 
-        inline friend std::ostream& operator << ( std::ostream& os, Columns const& cols ) {
+	auto operator += (Column const& col) -> Columns& {
+		m_columns.push_back(col);
+		return *this;
+	}
+	auto operator + (Column const& col) -> Columns {
+		Columns combined = *this;
+		combined += col;
+		return combined;
+	}
 
-            bool first = true;
-            for( auto line : cols ) {
-                if( first )
-                    first = false;
-                else
-                    os << "\n";
-                os << line;
-            }
-            return os;
-        }
+	inline friend std::ostream& operator << (std::ostream& os, Columns const& cols) {
 
-        auto toString() const -> std::string {
-            std::ostringstream oss;
-            oss << *this;
-            return oss.str();
-        }
-    };
+		bool first = true;
+		for (auto line : cols) {
+			if (first)
+				first = false;
+			else
+				os << "\n";
+			os << line;
+		}
+		return os;
+	}
 
-    inline auto Column::operator + ( Column const& other ) -> Columns {
-        Columns cols;
-        cols += *this;
-        cols += other;
-        return cols;
-    }
-}}} // namespace Catch::clara::TextFlow
+	auto toString() const -> std::string {
+		std::ostringstream oss;
+		oss << *this;
+		return oss.str();
+	}
+};
 
+inline auto Column::operator + (Column const& other) -> Columns {
+	Columns cols;
+	cols += *this;
+	cols += other;
+	return cols;
+}
+}
+
+}
+}
 #endif // CATCH_CLARA_TEXTFLOW_HPP_INCLUDED
 
 // ----------- end of #include from clara_textflow.hpp -----------
 // ........... back in clara.hpp
 
-
+#include <cctype>
+#include <string>
 #include <memory>
 #include <set>
 #include <algorithm>
@@ -395,11 +408,9 @@
         std::vector<std::string> m_args;
 
     public:
-        Args( int argc, char *argv[] ) {
-            m_exeName = argv[0];
-            for( int i = 1; i < argc; ++i )
-                m_args.push_back( argv[i] );
-        }
+        Args( int argc, char const* const* argv )
+            : m_exeName(argv[0]),
+              m_args(argv + 1, argv + argc) {}
 
         Args( std::initializer_list<std::string> args )
         :   m_exeName( *args.begin() ),
@@ -586,14 +597,13 @@
 
     protected:
         void enforceOk() const override {
-            switch( m_type ) {
-                case ResultBase::LogicError:
-                    Exception::doThrow( std::logic_error( m_errorMessage ) );
-                case ResultBase::RuntimeError:
-                    Exception::doThrow( std::runtime_error( m_errorMessage ) );
-                case ResultBase::Ok:
-                    break;
-            }
+
+            // Errors shouldn't reach this point, but if they do
+            // the actual error message will be in m_errorMessage
+            assert( m_type != ResultBase::LogicError );
+            assert( m_type != ResultBase::RuntimeError );
+            if( m_type != ResultBase::Ok )
+                std::abort();
         }
 
         std::string m_errorMessage; // Only populated if resultType is an error
@@ -654,7 +664,7 @@
     }
     inline auto convertInto( std::string const &source, bool &target ) -> ParserResult {
         std::string srcLC = source;
-        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( ::tolower(c) ); } );
+        std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast<char>( std::tolower(c) ); } );
         if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on")
             target = true;
         else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off")
@@ -663,6 +673,16 @@
             return ParserResult::runtimeError( "Expected a boolean value but did not recognise: '" + source + "'" );
         return ParserResult::ok( ParseResultType::Matched );
     }
+#ifdef CLARA_CONFIG_OPTIONAL_TYPE
+    template<typename T>
+    inline auto convertInto( std::string const &source, CLARA_CONFIG_OPTIONAL_TYPE<T>& target ) -> ParserResult {
+        T temp;
+        auto result = convertInto( source, temp );
+        if( result )
+            target = std::move(temp);
+        return result;
+    }
+#endif // CLARA_CONFIG_OPTIONAL_TYPE
 
     struct NonCopyable {
         NonCopyable() = default;
@@ -672,20 +692,17 @@
         NonCopyable &operator=( NonCopyable && ) = delete;
     };
 
-    struct BoundValueRefBase;
-
     struct BoundRef : NonCopyable {
         virtual ~BoundRef() = default;
         virtual auto isContainer() const -> bool { return false; }
-        virtual auto isValueRefBase() const -> bool = 0;  // Support for compiling without rtti.
+        virtual auto isFlag() const -> bool { return false; }
     };
     struct BoundValueRefBase : BoundRef {
         virtual auto setValue( std::string const &arg ) -> ParserResult = 0;
-        virtual auto isValueRefBase() const -> bool { return true; }
     };
     struct BoundFlagRefBase : BoundRef {
         virtual auto setFlag( bool flag ) -> ParserResult = 0;
-        virtual auto isValueRefBase() const -> bool { return false; }
+        virtual auto isFlag() const -> bool { return true; }
     };
 
     template<typename T>
@@ -917,7 +934,7 @@
             if( token.type != TokenType::Argument )
                 return InternalParseResult::ok( ParseState( ParseResultType::NoMatch, remainingTokens ) );
 
-            assert( m_ref.get()->isValueRefBase() );
+            assert( !m_ref->isFlag() );
             auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
 
             auto result = valueRef->setValue( remainingTokens->token );
@@ -993,20 +1010,14 @@
             if( remainingTokens && remainingTokens->type == TokenType::Option ) {
                 auto const &token = *remainingTokens;
                 if( isMatch(token.token ) ) {
-                    if ( !m_ref.get()->isValueRefBase() ) {
-                        detail::BoundFlagRefBase* flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
-#if CATCH_CONFIG_USE_RTTI
-                        assert( dynamic_cast<detail::BoundFlagRefBase*>( m_ref.get() ) );
-#endif
+                    if( m_ref->isFlag() ) {
+                        auto flagRef = static_cast<detail::BoundFlagRefBase*>( m_ref.get() );
                         auto result = flagRef->setFlag( true );
                         if( !result )
                             return InternalParseResult( result );
                         if( result.value() == ParseResultType::ShortCircuitAll )
                             return InternalParseResult::ok( ParseState( result.value(), remainingTokens ) );
                     } else {
-#if CATCH_CONFIG_USE_RTTI
-                        assert( dynamic_cast<detail::BoundValueRefBase*>( m_ref.get() ) );
-#endif
                         auto valueRef = static_cast<detail::BoundValueRefBase*>( m_ref.get() );
                         ++remainingTokens;
                         if( !remainingTokens )
diff --git a/include/internal/catch_approx.cpp b/include/internal/catch_approx.cpp
index 20f7b16..a7d7111 100644
--- a/include/internal/catch_approx.cpp
+++ b/include/internal/catch_approx.cpp
@@ -7,6 +7,7 @@
  */
 
 #include "catch_approx.h"
+#include "catch_enforce.h"
 
 #include <cmath>
 #include <limits>
@@ -35,6 +36,13 @@
         return Approx( 0 );
     }
 
+    Approx Approx::operator-() const {
+        auto temp(*this);
+        temp.m_value = -temp.m_value;
+        return temp;
+    }
+
+
     std::string Approx::toString() const {
         ReusableStringStream rss;
         rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
@@ -47,8 +55,31 @@
         return marginComparison(m_value, other, m_margin) || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(m_value)));
     }
 
+    void Approx::setMargin(double margin) {
+        CATCH_ENFORCE(margin >= 0,
+            "Invalid Approx::margin: " << margin << '.'
+            << " Approx::Margin has to be non-negative.");
+        m_margin = margin;
+    }
+
+    void Approx::setEpsilon(double epsilon) {
+        CATCH_ENFORCE(epsilon >= 0 && epsilon <= 1.0,
+            "Invalid Approx::epsilon: " << epsilon << '.'
+            << " Approx::epsilon has to be in [0, 1]");
+        m_epsilon = epsilon;
+    }
+
 } // end namespace Detail
 
+namespace literals {
+    Detail::Approx operator "" _a(long double val) {
+        return Detail::Approx(val);
+    }
+    Detail::Approx operator "" _a(unsigned long long val) {
+        return Detail::Approx(val);
+    }
+} // end namespace literals
+
 std::string StringMaker<Catch::Detail::Approx>::convert(Catch::Detail::Approx const& value) {
     return value.toString();
 }
diff --git a/include/internal/catch_approx.h b/include/internal/catch_approx.h
index 4b58f46..4522e5a 100644
--- a/include/internal/catch_approx.h
+++ b/include/internal/catch_approx.h
@@ -8,11 +8,9 @@
 #ifndef TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
 
-#include "catch_common.h"
 #include "catch_tostring.h"
 
 #include <type_traits>
-#include <stdexcept>
 
 namespace Catch {
 namespace Detail {
@@ -20,18 +18,26 @@
     class Approx {
     private:
         bool equalityComparisonImpl(double other) const;
+        // Validates the new margin (margin >= 0)
+        // out-of-line to avoid including stdexcept in the header
+        void setMargin(double margin);
+        // Validates the new epsilon (0 < epsilon < 1)
+        // out-of-line to avoid including stdexcept in the header
+        void setEpsilon(double epsilon);
 
     public:
         explicit Approx ( double value );
 
         static Approx custom();
 
+        Approx operator-() const;
+
         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
         Approx operator()( T const& value ) {
             Approx approx( static_cast<double>(value) );
-            approx.epsilon( m_epsilon );
-            approx.margin( m_margin );
-            approx.scale( m_scale );
+            approx.m_epsilon = m_epsilon;
+            approx.m_margin = m_margin;
+            approx.m_scale = m_scale;
             return approx;
         }
 
@@ -84,27 +90,14 @@
         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
         Approx& epsilon( T const& newEpsilon ) {
             double epsilonAsDouble = static_cast<double>(newEpsilon);
-            if( epsilonAsDouble < 0 || epsilonAsDouble > 1.0 ) {
-              Exception::doThrow( std::domain_error
-                    (   "Invalid Approx::epsilon: " +
-                        Catch::Detail::stringify( epsilonAsDouble ) +
-                        ", Approx::epsilon has to be between 0 and 1" ) );
-            }
-            m_epsilon = epsilonAsDouble;
+            setEpsilon(epsilonAsDouble);
             return *this;
         }
 
         template <typename T, typename = typename std::enable_if<std::is_constructible<double, T>::value>::type>
         Approx& margin( T const& newMargin ) {
             double marginAsDouble = static_cast<double>(newMargin);
-            if( marginAsDouble < 0 ) {
-                Exception::doThrow( std::domain_error
-                    (   "Invalid Approx::margin: " +
-                         Catch::Detail::stringify( marginAsDouble ) +
-                         ", Approx::Margin has to be non-negative." ) );
-
-            }
-            m_margin = marginAsDouble;
+            setMargin(marginAsDouble);
             return *this;
         }
 
@@ -122,7 +115,12 @@
         double m_scale;
         double m_value;
     };
-}
+} // end namespace Detail
+
+namespace literals {
+    Detail::Approx operator "" _a(long double val);
+    Detail::Approx operator "" _a(unsigned long long val);
+} // end namespace literals
 
 template<>
 struct StringMaker<Catch::Detail::Approx> {
diff --git a/include/internal/catch_assertionhandler.cpp b/include/internal/catch_assertionhandler.cpp
index e4a107e..fd14c85 100644
--- a/include/internal/catch_assertionhandler.cpp
+++ b/include/internal/catch_assertionhandler.cpp
@@ -15,12 +15,15 @@
 #include "catch_interfaces_registry_hub.h"
 #include "catch_capture_matchers.h"
 #include "catch_run_context.h"
+#include "catch_enforce.h"
 
 namespace Catch {
 
-    auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
-        expr.streamReconstructedExpression( os );
-        return os;
+    namespace {
+        auto operator <<( std::ostream& os, ITransientExpression const& expr ) -> std::ostream& {
+            expr.streamReconstructedExpression( os );
+            return os;
+        }
     }
 
     LazyExpression::LazyExpression( bool isNegated )
@@ -50,7 +53,7 @@
     }
 
     AssertionHandler::AssertionHandler
-        (   StringRef macroName,
+        (   StringRef const& macroName,
             SourceLineInfo const& lineInfo,
             StringRef capturedExpression,
             ResultDisposition::Flags resultDisposition )
@@ -79,8 +82,13 @@
             // (To go back to the test and change execution, jump over the throw, next)
             CATCH_BREAK_INTO_DEBUGGER();
         }
-        if( m_reaction.shouldThrow )
-            Exception::doThrow( Catch::TestFailureException() );
+        if (m_reaction.shouldThrow) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+            throw Catch::TestFailureException();
+#else
+            CATCH_ERROR( "Test failure requires aborting test!" );
+#endif
+        }
     }
     void AssertionHandler::setCompleted() {
         m_completed = true;
@@ -107,7 +115,7 @@
 
     // This is the overload that takes a string and infers the Equals matcher from it
     // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
-    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString  ) {
+    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString  ) {
         handleExceptionMatchExpr( handler, Matchers::Equals( str ), matcherString );
     }
 
diff --git a/include/internal/catch_assertionhandler.h b/include/internal/catch_assertionhandler.h
index cadc78f..3089e66 100644
--- a/include/internal/catch_assertionhandler.h
+++ b/include/internal/catch_assertionhandler.h
@@ -49,7 +49,7 @@
 
     public:
         AssertionHandler
-            (   StringRef macroName,
+            (   StringRef const& macroName,
                 SourceLineInfo const& lineInfo,
                 StringRef capturedExpression,
                 ResultDisposition::Flags resultDisposition );
@@ -81,7 +81,7 @@
         auto allowThrows() const -> bool;
     };
 
-    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef matcherString );
+    void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str, StringRef const& matcherString );
 
 } // namespace Catch
 
diff --git a/include/internal/catch_assertionresult.cpp b/include/internal/catch_assertionresult.cpp
index ec32c66..4ce0718 100644
--- a/include/internal/catch_assertionresult.cpp
+++ b/include/internal/catch_assertionresult.cpp
@@ -65,9 +65,9 @@
             expr = m_info.capturedExpression;
         else {
             expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
-            expr += m_info.macroName.c_str();
+            expr += m_info.macroName;
             expr += "( ";
-            expr += m_info.capturedExpression.c_str();
+            expr += m_info.capturedExpression;
             expr += " )";
         }
         return expr;
diff --git a/include/internal/catch_capture.hpp b/include/internal/catch_capture.hpp
index 29ad326..51fa035 100644
--- a/include/internal/catch_capture.hpp
+++ b/include/internal/catch_capture.hpp
@@ -9,8 +9,9 @@
 #define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
 
 #include "catch_assertionhandler.h"
-#include "catch_message.h"
 #include "catch_interfaces_capture.h"
+#include "catch_message.h"
+#include "catch_stringref.h"
 
 #if !defined(CATCH_CONFIG_DISABLE)
 
@@ -20,14 +21,7 @@
   #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"
 #endif
 
-#if defined(CATCH_CONFIG_FAST_COMPILE)
-
-struct ConvertToAny {
-  template <typename T>
-  operator T() {
-    return T{};
-  }
-};
+#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
 
 ///////////////////////////////////////////////////////////////////////////////
 // Another way to speed-up compilation is to omit local try-catch for REQUIRE*
@@ -37,8 +31,8 @@
 
 #else // CATCH_CONFIG_FAST_COMPILE
 
-#define INTERNAL_CATCH_TRY CATCH_INTERNAL_TRY
-#define INTERNAL_CATCH_CATCH( handler ) CATCH_INTERNAL_CATCH_ALL() { handler.handleUnexpectedInflightException(); }
+#define INTERNAL_CATCH_TRY try
+#define INTERNAL_CATCH_CATCH( handler ) catch(...) { handler.handleUnexpectedInflightException(); }
 
 #endif
 
@@ -47,14 +41,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
         INTERNAL_CATCH_TRY { \
             CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
             catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); \
             CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
         } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
         INTERNAL_CATCH_REACT( catchAssertionHandler ) \
-    } while( (void)0, false && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
+    } while( (void)0, (false) && static_cast<bool>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
     // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -67,15 +61,23 @@
     INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
     if( !Catch::getResultCapture().lastAssertionPassed() )
 
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+
+#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... )
+#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... )
+#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr )
+
+#else
+
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
-        CATCH_INTERNAL_TRY { \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
+        try { \
             static_cast<void>(__VA_ARGS__); \
             catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
         } \
-        CATCH_INTERNAL_CATCH_ALL() { \
+        catch( ... ) { \
             catchAssertionHandler.handleUnexpectedInflightException(); \
         } \
         INTERNAL_CATCH_REACT( catchAssertionHandler ) \
@@ -84,7 +86,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
         if( catchAssertionHandler.allowThrows() ) \
             try { \
                 static_cast<void>(__VA_ARGS__); \
@@ -101,7 +103,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
         if( catchAssertionHandler.allowThrows() ) \
             try { \
                 static_cast<void>(expr); \
@@ -118,31 +120,41 @@
         INTERNAL_CATCH_REACT( catchAssertionHandler ) \
     } while( false )
 
+#endif  // CATCH_CONFIG_DISABLE_EXCEPTIONS
 
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
         catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
         INTERNAL_CATCH_REACT( catchAssertionHandler ) \
     } while( false )
 
 ///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
+    auto varName = Catch::Capturer( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info, #__VA_ARGS__ ); \
+    varName.captureValues( 0, __VA_ARGS__ )
+
+///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_INFO( macroName, log ) \
-    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log );
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
+    Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
 
 ///////////////////////////////////////////////////////////////////////////////
 // Although this is matcher-based, it can be used with just a string
 #define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
         if( catchAssertionHandler.allowThrows() ) \
             try { \
                 static_cast<void>(__VA_ARGS__); \
                 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
             } \
             catch( ... ) { \
-                Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher ); \
+                Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher, #matcher##_catch_sr ); \
             } \
         else \
             catchAssertionHandler.handleThrowingCallSkipped(); \
diff --git a/include/internal/catch_capture_matchers.cpp b/include/internal/catch_capture_matchers.cpp
index 7ef1597..6f32044 100644
--- a/include/internal/catch_capture_matchers.cpp
+++ b/include/internal/catch_capture_matchers.cpp
@@ -13,9 +13,9 @@
     using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
 
     // This is the general overload that takes a any string matcher
-    // There is another overload, in catch_assertinhandler.h/.cpp, that only takes a string and infers
+    // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
     // the Equals matcher (so the header does not mention matchers)
-    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString  ) {
+    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  ) {
         std::string exceptionMessage = Catch::translateActiveException();
         MatchExpr<std::string, StringMatcher const&> expr( exceptionMessage, matcher, matcherString );
         handler.handleExpr( expr );
diff --git a/include/internal/catch_capture_matchers.h b/include/internal/catch_capture_matchers.h
index 3aeb276..0ced01d 100644
--- a/include/internal/catch_capture_matchers.h
+++ b/include/internal/catch_capture_matchers.h
@@ -11,8 +11,10 @@
 #include "catch_capture.hpp"
 #include "catch_matchers.h"
 #include "catch_matchers_floating.h"
+#include "catch_matchers_generic.hpp"
 #include "catch_matchers_string.h"
 #include "catch_matchers_vector.h"
+#include "catch_stringref.h"
 
 namespace Catch {
 
@@ -22,7 +24,7 @@
         MatcherT m_matcher;
         StringRef m_matcherString;
     public:
-        MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString )
+        MatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString )
         :   ITransientExpression{ true, matcher.match( arg ) },
             m_arg( arg ),
             m_matcher( matcher ),
@@ -41,10 +43,10 @@
 
     using StringMatcher = Matchers::Impl::MatcherBase<std::string>;
 
-    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef matcherString  );
+    void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher, StringRef const& matcherString  );
 
     template<typename ArgT, typename MatcherT>
-    auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef matcherString  ) -> MatchExpr<ArgT, MatcherT> {
+    auto makeMatchExpr( ArgT const& arg, MatcherT const& matcher, StringRef const& matcherString  ) -> MatchExpr<ArgT, MatcherT> {
         return MatchExpr<ArgT, MatcherT>( arg, matcher, matcherString );
     }
 
@@ -54,9 +56,9 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
-        CATCH_INTERNAL_TRY { \
-            catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher ) ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        INTERNAL_CATCH_TRY { \
+            catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher, #matcher##_catch_sr ) ); \
         } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
         INTERNAL_CATCH_REACT( catchAssertionHandler ) \
     } while( false )
@@ -65,14 +67,14 @@
 ///////////////////////////////////////////////////////////////////////////////
 #define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
     do { \
-        Catch::AssertionHandler catchAssertionHandler( macroName, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
+        Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
         if( catchAssertionHandler.allowThrows() ) \
             try { \
                 static_cast<void>(__VA_ARGS__ ); \
                 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
             } \
             catch( exceptionType const& ex ) { \
-                catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher ) ); \
+                catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher, #matcher##_catch_sr ) ); \
             } \
             catch( ... ) { \
                 catchAssertionHandler.handleUnexpectedInflightException(); \
diff --git a/include/internal/catch_commandline.cpp b/include/internal/catch_commandline.cpp
index c0231d1..66759eb 100644
--- a/include/internal/catch_commandline.cpp
+++ b/include/internal/catch_commandline.cpp
@@ -10,6 +10,9 @@
 
 #include "catch_string_manip.h"
 
+#include "catch_interfaces_registry_hub.h"
+#include "catch_interfaces_reporter.h"
+
 #include <fstream>
 #include <ctime>
 
@@ -20,9 +23,19 @@
         using namespace clara;
 
         auto const setWarning = [&]( std::string const& warning ) {
-                if( warning != "NoAssertions" )
+                auto warningSet = [&]() {
+                    if( warning == "NoAssertions" )
+                        return WarnAbout::NoAssertions;
+
+                    if ( warning == "NoTests" )
+                        return WarnAbout::NoTests;
+
+                    return WarnAbout::Nothing;
+                }();
+
+                if (warningSet == WarnAbout::Nothing)
                     return ParserResult::runtimeError( "Unrecognised warning: '" + warning + "'" );
-                config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+                config.warnings = static_cast<WarnAbout::What>( config.warnings | warningSet );
                 return ParserResult::ok( ParseResultType::Matched );
             };
         auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
@@ -95,6 +108,18 @@
                 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + "'" );
             return ParserResult::ok( ParseResultType::Matched );
         };
+        auto const setReporter = [&]( std::string const& reporter ) {
+            IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+
+            auto lcReporter = toLower( reporter );
+            auto result = factories.find( lcReporter );
+
+            if( factories.end() != result )
+                config.reporterName = lcReporter;
+            else
+                return ParserResult::runtimeError( "Unrecognized reporter, '" + reporter + "'. Check available with --list-reporters" );
+            return ParserResult::ok( ParseResultType::Matched );
+        };
 
         auto cli
             = ExeName( config.processName )
@@ -120,7 +145,7 @@
             | Opt( config.outputFilename, "filename" )
                 ["-o"]["--out"]
                 ( "output filename" )
-            | Opt( config.reporterNames, "name" )
+            | Opt( setReporter, "name" )
                 ["-r"]["--reporter"]
                 ( "reporter to use (defaults to console)" )
             | Opt( config.name, "name" )
diff --git a/include/internal/catch_common.cpp b/include/internal/catch_common.cpp
index c271146..b2fca4c 100644
--- a/include/internal/catch_common.cpp
+++ b/include/internal/catch_common.cpp
@@ -22,7 +22,9 @@
         return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
     }
     bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
-        return line < other.line || ( line == other.line && (std::strcmp(file, other.file) < 0));
+        // We can assume that the same file will usually have the same pointer.
+        // Thus, if the pointers are the same, there is no point in calling the strcmp
+        return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
     }
 
     std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
diff --git a/include/internal/catch_common.h b/include/internal/catch_common.h
index 8294a86..e474562 100644
--- a/include/internal/catch_common.h
+++ b/include/internal/catch_common.h
@@ -22,6 +22,10 @@
 #include <string>
 #include <cstdint>
 
+// We need a dummy global operator<< so we can bring it into Catch namespace later
+struct Catch_global_namespace_dummy {};
+std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
+
 namespace Catch {
 
     struct CaseSensitive { enum Choice {
@@ -48,10 +52,10 @@
             line( _line )
         {}
 
-        SourceLineInfo( SourceLineInfo const& other )        = default;
-        SourceLineInfo( SourceLineInfo && )                  = default;
-        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
-        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+        SourceLineInfo( SourceLineInfo const& other )            = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& )     = default;
+        SourceLineInfo( SourceLineInfo&& )              noexcept = default;
+        SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default;
 
         bool empty() const noexcept;
         bool operator == ( SourceLineInfo const& other ) const noexcept;
@@ -63,6 +67,11 @@
 
     std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
 
+    // Bring in operator<< from global namespace into Catch namespace
+    // This is necessary because the overload of operator<< above makes
+    // lookup stop at namespace Catch
+    using ::operator<<;
+
     // Use this in variadic streaming macros to allow
     //    >> +StreamEndStop
     // as well as
@@ -74,40 +83,10 @@
     T const& operator + ( T const& value, StreamEndStop ) {
         return value;
     }
-
-
-    // A replacement for the "throw" keyword which is illegal when
-    // exceptions are disabled with -fno-exceptions.
-    struct Exception {
-        template <typename E>
-        [[noreturn]] static void doThrow(E&& e) {
-#if CATCH_CONFIG_USE_EXCEPTIONS
-            throw std::forward<E>(e);
-#else
-            // "throw" keyword is unsupported when exceptions are disabled.
-            // Immediately terminate instead.
-            (void)e;  // error: unused parameter 'e' [-Werror,-Wunused-parameter]
-            std::terminate();
-#endif
-        }
-    };
 }
 
 #define CATCH_INTERNAL_LINEINFO \
     ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
 
-#if CATCH_CONFIG_USE_EXCEPTIONS
-#  define CATCH_INTERNAL_TRY try
-#  define CATCH_INTERNAL_CATCH( type, var) catch( type var )
-#  define CATCH_INTERNAL_CATCH_UNNAMED( type ) catch( type )
-#  define CATCH_INTERNAL_CATCH_ALL() catch( ... )
-#else
-// 'try' and 'catch' (and 'throw') keywords are illegal with -fno-exceptions.
-#  define CATCH_INTERNAL_TRY if ((true))
-#  define CATCH_INTERNAL_CATCH( typ, var ) while ((false)) for ( typename std::remove_reference<typ>::type var ; ; )
-#  define CATCH_INTERNAL_CATCH_UNNAMED( type ) while ((false))
-#  define CATCH_INTERNAL_CATCH_ALL() while ((false))
-#endif
-
 #endif // TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
 
diff --git a/include/internal/catch_compiler_capabilities.h b/include/internal/catch_compiler_capabilities.h
index 0ee2f49..012bf46 100644
--- a/include/internal/catch_compiler_capabilities.h
+++ b/include/internal/catch_compiler_capabilities.h
@@ -14,6 +14,7 @@
 // CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported?
 // CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
 // CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
+// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
 // ****************
 // Note to maintainers: if new toggles are added please document them
 // in configuration.md, too
@@ -24,14 +25,15 @@
 // Many features, at point of detection, define an _INTERNAL_ macro, so they
 // can be combined, en-mass, with the _NO_ forms later.
 
+#include "catch_platform.h"
 
 #ifdef __cplusplus
 
-#  if __cplusplus >= 201402L
+#  if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L)
 #    define CATCH_CPP14_OR_GREATER
 #  endif
 
-#  if __cplusplus >= 201703L
+#  if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
 #    define CATCH_CPP17_OR_GREATER
 #  endif
 
@@ -56,25 +58,25 @@
 #       define CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
             _Pragma( "clang diagnostic pop" )
 
-#if  !__has_feature(cxx_rtti)
-#    define CATCH_CONFIG_USE_RTTI 0
-#endif
-
-#if !__has_feature(cxx_exceptions)
-#    define CATCH_CONFIG_USE_EXCEPTIONS 0
-#endif
+#       define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+            _Pragma( "clang diagnostic push" ) \
+            _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
+#       define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS \
+            _Pragma( "clang diagnostic pop" )
 
 #endif // __clang__
 
 
 ////////////////////////////////////////////////////////////////////////////////
+// Assume that non-Windows platforms support posix signals by default
+#if !defined(CATCH_PLATFORM_WINDOWS)
+    #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
 // We know some environments not to support full POSIX signals
-#if defined(__CYGWIN__) || defined(__QNX__)
-
-#   if !defined(CATCH_CONFIG_POSIX_SIGNALS)
-#       define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
-#   endif
-
+#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__)
+    #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
 #endif
 
 #ifdef __OS400__
@@ -83,13 +85,38 @@
 #endif
 
 ////////////////////////////////////////////////////////////////////////////////
+// Android somehow still does not support std::to_string
+#if defined(__ANDROID__)
+#    define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Not all Windows environments support SEH properly
+#if defined(__MINGW32__)
+#    define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// PS4
+#if defined(__ORBIS__)
+#    define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
 // Cygwin
 #ifdef __CYGWIN__
 
 // Required for some versions of Cygwin to declare gettimeofday
 // see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
 #   define _BSD_SOURCE
+// some versions of cygwin (most) do not support std::to_string. Use the libstd check. 
+// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
+# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
+	       && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
 
+#	define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
+
+# endif
 #endif // __CYGWIN__
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -109,9 +136,34 @@
 #    define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
 #  endif
 
+// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
+// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
+// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
+#  if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
+#    define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#  endif
+
 #endif // _MSC_VER
 
 ////////////////////////////////////////////////////////////////////////////////
+// Check if we are compiled with -fno-exceptions or equivalent
+#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
+#  define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// DJGPP
+#ifdef __DJGPP__
+#  define CATCH_INTERNAL_CONFIG_NO_WCHAR
+#endif // __DJGPP__
+
+////////////////////////////////////////////////////////////////////////////////
+// Embarcadero C++Build
+#if defined(__BORLANDC__)
+    #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
 
 // Use of __COUNTER__ is suppressed during code analysis in
 // CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly
@@ -122,21 +174,93 @@
     #define CATCH_INTERNAL_CONFIG_COUNTER
 #endif
 
+////////////////////////////////////////////////////////////////////////////////
+// Check if string_view is available and usable
+// The check is split apart to work around v140 (VS2015) preprocessor issue...
+#if defined(__has_include)
+#if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
+#    define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
+#endif
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// Check if optional is available and usable
+#if defined(__has_include)
+#  if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+#    define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
+#  endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // __has_include
+
+////////////////////////////////////////////////////////////////////////////////
+// Check if variant is available and usable
+#if defined(__has_include)
+#  if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#    if defined(__clang__) && (__clang_major__ < 8)
+       // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
+       // fix should be in clang 8, workaround in libstdc++ 8.2
+#      include <ciso646>
+#      if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+#        define CATCH_CONFIG_NO_CPP17_VARIANT
+#      else
+#        define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+#      endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
+#    else
+#      define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
+#    endif // defined(__clang__) && (__clang_major__ < 8)
+#  endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
+#endif // __has_include
+
+
 #if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER)
 #   define CATCH_CONFIG_COUNTER
 #endif
-#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH)
+#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
 #   define CATCH_CONFIG_WINDOWS_SEH
 #endif
 // This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
-#if !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
+#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
 #   define CATCH_CONFIG_POSIX_SIGNALS
 #endif
+// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions.
+#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR)
+#   define CATCH_CONFIG_WCHAR
+#endif
 
-#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_INTERNAL_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
+#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
+#    define CATCH_CONFIG_CPP11_TO_STRING
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#  define CATCH_CONFIG_CPP17_OPTIONAL
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
 #  define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
 #endif
 
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
+#  define CATCH_CONFIG_CPP17_STRING_VIEW
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
+#  define CATCH_CONFIG_CPP17_VARIANT
+#endif
+
+#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+#  define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
+#  define CATCH_CONFIG_NEW_CAPTURE
+#endif
+
+#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#  define CATCH_CONFIG_DISABLE_EXCEPTIONS
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+#  define CATCH_CONFIG_POLYFILL_ISNAN
+#endif
 
 #if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
 #   define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
@@ -146,13 +270,23 @@
 #   define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
 #   define CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
 #endif
-
-#if !defined(CATCH_CONFIG_USE_RTTI)
-#  define CATCH_CONFIG_USE_RTTI 1
+#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS)
+#   define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS
+#   define CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
 #endif
 
-#if !defined(CATCH_CONFIG_USE_EXCEPTIONS)
-#  define CATCH_CONFIG_USE_EXCEPTIONS 1
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+#define CATCH_TRY if ((true))
+#define CATCH_CATCH_ALL if ((false))
+#define CATCH_CATCH_ANON(type) if ((false))
+#else
+#define CATCH_TRY try
+#define CATCH_CATCH_ALL catch (...)
+#define CATCH_CATCH_ANON(type) catch (type)
+#endif
+
+#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
+#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
 #endif
 
 #endif // TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
diff --git a/include/internal/catch_config.cpp b/include/internal/catch_config.cpp
index 67d2b27..e8ad2a8 100644
--- a/include/internal/catch_config.cpp
+++ b/include/internal/catch_config.cpp
@@ -15,12 +15,16 @@
     :   m_data( data ),
         m_stream( openStream() )
     {
-        if( !data.testsOrTags.empty() ) {
-            TestSpecParser parser( ITagAliasRegistry::get() );
+        TestSpecParser parser(ITagAliasRegistry::get());
+        if (data.testsOrTags.empty()) {
+            parser.parse("~[.]"); // All not hidden tests
+        }
+        else {
+            m_hasTestFilters = true;
             for( auto const& testOrTags : data.testsOrTags )
                 parser.parse( testOrTags );
-            m_testSpec = parser.testSpec();
         }
+        m_testSpec = parser.testSpec();
     }
 
     std::string const& Config::getFilename() const {
@@ -33,11 +37,13 @@
     bool Config::listReporters() const      { return m_data.listReporters; }
 
     std::string Config::getProcessName() const { return m_data.processName; }
+    std::string const& Config::getReporterName() const { return m_data.reporterName; }
 
-    std::vector<std::string> const& Config::getReporterNames() const { return m_data.reporterNames; }
+    std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
     std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
 
     TestSpec const& Config::testSpec() const { return m_testSpec; }
+    bool Config::hasTestFilters() const { return m_hasTestFilters; }
 
     bool Config::showHelp() const { return m_data.showHelp; }
 
@@ -46,7 +52,8 @@
     std::ostream& Config::stream() const               { return m_stream->stream(); }
     std::string Config::name() const                   { return m_data.name.empty() ? m_data.processName : m_data.name; }
     bool Config::includeSuccessfulResults() const      { return m_data.showSuccessfulTests; }
-    bool Config::warnAboutMissingAssertions() const    { return m_data.warnings & WarnAbout::NoAssertions; }
+    bool Config::warnAboutMissingAssertions() const    { return !!(m_data.warnings & WarnAbout::NoAssertions); }
+    bool Config::warnAboutNoTests() const              { return !!(m_data.warnings & WarnAbout::NoTests); }
     ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; }
     RunTests::InWhatOrder Config::runOrder() const     { return m_data.runOrder; }
     unsigned int Config::rngSeed() const               { return m_data.rngSeed; }
diff --git a/include/internal/catch_config.hpp b/include/internal/catch_config.hpp
index fcaa050..7bafc9c 100644
--- a/include/internal/catch_config.hpp
+++ b/include/internal/catch_config.hpp
@@ -54,8 +54,12 @@
         std::string outputFilename;
         std::string name;
         std::string processName;
+#ifndef CATCH_CONFIG_DEFAULT_REPORTER
+#define CATCH_CONFIG_DEFAULT_REPORTER "console"
+#endif
+        std::string reporterName = CATCH_CONFIG_DEFAULT_REPORTER;
+#undef CATCH_CONFIG_DEFAULT_REPORTER
 
-        std::vector<std::string> reporterNames;
         std::vector<std::string> testsOrTags;
         std::vector<std::string> sectionsToRun;
     };
@@ -76,11 +80,13 @@
         bool listReporters() const;
 
         std::string getProcessName() const;
+        std::string const& getReporterName() const;
 
-        std::vector<std::string> const& getReporterNames() const;
+        std::vector<std::string> const& getTestsOrTags() const;
         std::vector<std::string> const& getSectionsToRun() const override;
 
         virtual TestSpec const& testSpec() const override;
+        bool hasTestFilters() const override;
 
         bool showHelp() const;
 
@@ -90,6 +96,7 @@
         std::string name() const override;
         bool includeSuccessfulResults() const override;
         bool warnAboutMissingAssertions() const override;
+        bool warnAboutNoTests() const override;
         ShowDurations::OrNot showDurations() const override;
         RunTests::InWhatOrder runOrder() const override;
         unsigned int rngSeed() const override;
@@ -107,6 +114,7 @@
 
         std::unique_ptr<IStream const> m_stream;
         TestSpec m_testSpec;
+        bool m_hasTestFilters = false;
     };
 
 } // end namespace Catch
diff --git a/include/internal/catch_console_colour.cpp b/include/internal/catch_console_colour.cpp
index f692b5c..07072db 100644
--- a/include/internal/catch_console_colour.cpp
+++ b/include/internal/catch_console_colour.cpp
@@ -160,7 +160,8 @@
 
     private:
         void setColour( const char* _escapeCode ) {
-            Catch::cout() << '\033' << _escapeCode;
+            getCurrentContext().getConfig()->stream()
+                << '\033' << _escapeCode;
         }
     };
 
@@ -169,7 +170,12 @@
 #ifdef CATCH_PLATFORM_MAC
             !isDebuggerActive() &&
 #endif
-            isatty(STDOUT_FILENO);
+#if !(defined(__DJGPP__) && defined(__STRICT_ANSI__))
+            isatty(STDOUT_FILENO)
+#else
+            false
+#endif
+            ;
     }
     IColourImpl* platformColourInstance() {
         ErrnoGuard guard;
diff --git a/include/internal/catch_debug_console.cpp b/include/internal/catch_debug_console.cpp
index d817c56..5d25f65 100644
--- a/include/internal/catch_debug_console.cpp
+++ b/include/internal/catch_debug_console.cpp
@@ -9,21 +9,23 @@
 #include "catch_debug_console.h"
 #include "catch_stream.h"
 #include "catch_platform.h"
+#include "catch_windows_h_proxy.h"
 
 #ifdef CATCH_PLATFORM_WINDOWS
 
-#include "catch_windows_h_proxy.h"
-
     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
diff --git a/include/internal/catch_debugger.h b/include/internal/catch_debugger.h
index 7541984..db3ff68 100644
--- a/include/internal/catch_debugger.h
+++ b/include/internal/catch_debugger.h
@@ -38,12 +38,9 @@
 #endif
 
 #ifdef CATCH_TRAP
-    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { CATCH_TRAP(); }
+    #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
 #else
-    namespace Catch {
-        inline void doNothing() {}
-    }
-    #define CATCH_BREAK_INTO_DEBUGGER() Catch::doNothing()
+    #define CATCH_BREAK_INTO_DEBUGGER() []{}()
 #endif
 
 #endif // TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
diff --git a/include/internal/catch_decomposer.h b/include/internal/catch_decomposer.h
index 618a250..08075f0 100644
--- a/include/internal/catch_decomposer.h
+++ b/include/internal/catch_decomposer.h
@@ -10,6 +10,7 @@
 
 #include "catch_tostring.h"
 #include "catch_stringref.h"
+#include "catch_meta.hpp"
 
 #include <iosfwd>
 
@@ -19,6 +20,7 @@
 #pragma warning(disable:4018) // more "signed/unsigned mismatch"
 #pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
 #pragma warning(disable:4180) // qualifier applied to function type has no meaning
+#pragma warning(disable:4800) // Forcing result to true or false
 #endif
 
 namespace Catch {
@@ -62,6 +64,62 @@
             m_op( op ),
             m_rhs( rhs )
         {}
+
+        template<typename T>
+        auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename T>
+        auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<T>::value,
+            "chained comparisons are not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
     };
 
     template<typename LhsT>
@@ -74,7 +132,7 @@
 
     public:
         explicit UnaryExpr( LhsT lhs )
-        :   ITransientExpression{ false, lhs ? true : false },
+        :   ITransientExpression{ false, static_cast<bool>(lhs) },
             m_lhs( lhs )
         {}
     };
@@ -143,6 +201,20 @@
             return { static_cast<bool>(m_lhs <= rhs), m_lhs, "<=", rhs };
         }
 
+        template<typename RhsT>
+        auto operator && ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<RhsT>::value,
+            "operator&& is not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
+        template<typename RhsT>
+        auto operator || ( RhsT const& ) -> BinaryExpr<LhsT, RhsT const&> const {
+            static_assert(always_false<RhsT>::value,
+            "operator|| is not supported inside assertions, "
+            "wrap the expression inside parentheses, or decompose it");
+        }
+
         auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
             return UnaryExpr<LhsT>{ m_lhs };
         }
diff --git a/include/internal/catch_default_main.hpp b/include/internal/catch_default_main.hpp
index 4372e9c..17ad090 100644
--- a/include/internal/catch_default_main.hpp
+++ b/include/internal/catch_default_main.hpp
@@ -12,7 +12,7 @@
 
 #ifndef __OBJC__
 
-#if defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
+#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
 // Standard C/C++ Win32 Unicode wmain entry point
 extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) {
 #else
diff --git a/include/internal/catch_enforce.cpp b/include/internal/catch_enforce.cpp
new file mode 100644
index 0000000..f4db1c1
--- /dev/null
+++ b/include/internal/catch_enforce.cpp
@@ -0,0 +1,19 @@
+/*
+ *  Created by Martin on 03/09/2018.
+ *
+ *  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 "catch_enforce.h"
+
+namespace Catch {
+#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
+    [[noreturn]]
+    void throw_exception(std::exception const& e) {
+        Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
+                      << "The message was: " << e.what() << '\n';
+        std::terminate();
+    }
+#endif
+} // namespace Catch;
diff --git a/include/internal/catch_enforce.h b/include/internal/catch_enforce.h
index cd4202a..0069402 100644
--- a/include/internal/catch_enforce.h
+++ b/include/internal/catch_enforce.h
@@ -8,18 +8,35 @@
 #define TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
 
 #include "catch_common.h"
+#include "catch_compiler_capabilities.h"
 #include "catch_stream.h"
 
+
 #include <stdexcept>
-#include <iosfwd>
+
+namespace Catch {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+    template <typename Ex>
+    [[noreturn]]
+    void throw_exception(Ex const& e) {
+        throw e;
+    }
+#else // ^^ Exceptions are enabled //  Exceptions are disabled vv
+    [[noreturn]]
+    void throw_exception(std::exception const& e);
+#endif
+} // namespace Catch;
 
 #define CATCH_PREPARE_EXCEPTION( type, msg ) \
-    type( static_cast<std::ostringstream&&>( Catch::ReusableStringStream().get() << msg ).str() )
+    type( ( Catch::ReusableStringStream() << msg ).str() )
 #define CATCH_INTERNAL_ERROR( msg ) \
-    Exception::doThrow( CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg) );
+    Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::logic_error, CATCH_INTERNAL_LINEINFO << ": Internal Catch error: " << msg))
 #define CATCH_ERROR( msg ) \
-    Exception::doThrow( CATCH_PREPARE_EXCEPTION( std::domain_error, msg ) )
+    Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::domain_error, msg ))
+#define CATCH_RUNTIME_ERROR( msg ) \
+    Catch::throw_exception(CATCH_PREPARE_EXCEPTION( std::runtime_error, msg ))
 #define CATCH_ENFORCE( condition, msg ) \
     do{ if( !(condition) ) CATCH_ERROR( msg ); } while(false)
 
+
 #endif // TWOBLUECUBES_CATCH_ENFORCE_H_INCLUDED
diff --git a/include/internal/catch_exception_translator_registry.cpp b/include/internal/catch_exception_translator_registry.cpp
index f048f67..cef36e5 100644
--- a/include/internal/catch_exception_translator_registry.cpp
+++ b/include/internal/catch_exception_translator_registry.cpp
@@ -6,8 +6,10 @@
  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  */
 
-#include "catch_assertionhandler.h"
 #include "catch_exception_translator_registry.h"
+#include "catch_assertionhandler.h"
+#include "catch_compiler_capabilities.h"
+#include "catch_enforce.h"
 
 #ifdef __OBJC__
 #import "Foundation/Foundation.h"
@@ -22,8 +24,9 @@
         m_translators.push_back( std::unique_ptr<const IExceptionTranslator>( translator ) );
     }
 
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
     std::string ExceptionTranslatorRegistry::translateActiveException() const {
-        CATCH_INTERNAL_TRY {
+        try {
 #ifdef __OBJC__
             // In Objective-C try objective-c exceptions first
             @try {
@@ -47,27 +50,40 @@
             return tryTranslators();
 #endif
         }
-        CATCH_INTERNAL_CATCH_UNNAMED( TestFailureException& ) {
+        catch( TestFailureException& ) {
             std::rethrow_exception(std::current_exception());
         }
-        CATCH_INTERNAL_CATCH( std::exception&, ex ) {
+        catch( std::exception& ex ) {
             return ex.what();
         }
-        CATCH_INTERNAL_CATCH( std::string&, msg ) {
+        catch( std::string& msg ) {
             return msg;
         }
-        CATCH_INTERNAL_CATCH( const char*, msg ) {
+        catch( const char* msg ) {
             return msg;
         }
-        CATCH_INTERNAL_CATCH_ALL() {
+        catch(...) {
             return "Unknown exception";
         }
     }
 
     std::string ExceptionTranslatorRegistry::tryTranslators() const {
-        if( m_translators.empty() )
+        if (m_translators.empty()) {
             std::rethrow_exception(std::current_exception());
-        else
-            return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() );
+        } else {
+            return m_translators[0]->translate(m_translators.begin() + 1, m_translators.end());
+        }
     }
+
+#else // ^^ Exceptions are enabled // Exceptions are disabled vv
+    std::string ExceptionTranslatorRegistry::translateActiveException() const {
+        CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+    }
+
+    std::string ExceptionTranslatorRegistry::tryTranslators() const {
+        CATCH_INTERNAL_ERROR("Attempted to use exception translators under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
+    }
+#endif
+
+
 }
diff --git a/include/internal/catch_fatal_condition.cpp b/include/internal/catch_fatal_condition.cpp
index 55ee539..24e16d3 100644
--- a/include/internal/catch_fatal_condition.cpp
+++ b/include/internal/catch_fatal_condition.cpp
@@ -17,24 +17,18 @@
 #    pragma GCC diagnostic ignored "-Wmissing-field-initializers"
 #endif
 
-#if (defined(CATCH_PLATFORM_WINDOWS) && defined(CATCH_CONFIG_WINDOWS_SEH)) || defined(CATCH_CONFIG_POSIX_SIGNALS)
+#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
+
 namespace {
     // Report the error condition
     void reportFatal( char const * const message ) {
         Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
     }
 }
-#endif
 
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+#endif // signals/SEH handling
 
-#  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
-
-namespace Catch {
-    void FatalConditionHandler::reset() {}
-}
-
-#  else // CATCH_CONFIG_WINDOWS_SEH is defined
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
 
 namespace Catch {
     struct SignalDefs { DWORD id; const char* name; };
@@ -74,7 +68,6 @@
 
     void FatalConditionHandler::reset() {
         if (isSet) {
-            // Unregister handler and restore the old guarantee
             RemoveVectoredExceptionHandler(exceptionHandlerHandle);
             SetThreadStackGuarantee(&guaranteeSize);
             exceptionHandlerHandle = nullptr;
@@ -93,20 +86,7 @@
 
 } // namespace Catch
 
-#  endif // CATCH_CONFIG_WINDOWS_SEH
-
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
-
-#  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
-
-namespace Catch {
-    void FatalConditionHandler::reset() {}
-}
-
-
-#  else // CATCH_CONFIG_POSIX_SIGNALS is defined
-
-#include <signal.h>
+#elif defined( CATCH_CONFIG_POSIX_SIGNALS )
 
 namespace Catch {
 
@@ -114,6 +94,11 @@
         int id;
         const char* name;
     };
+    
+    // 32kb for the alternate stack seems to be sufficient. However, this value
+    // is experimentally determined, so that's not guaranteed.
+    constexpr static std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ;
+
     static SignalDefs signalDefs[] = {
         { SIGINT,  "SIGINT - Terminal interrupt signal" },
         { SIGILL,  "SIGILL - Illegal instruction signal" },
@@ -141,7 +126,7 @@
         isSet = true;
         stack_t sigStack;
         sigStack.ss_sp = altStackMem;
-        sigStack.ss_size = SIGSTKSZ;
+        sigStack.ss_size = sigStackSize;
         sigStack.ss_flags = 0;
         sigaltstack(&sigStack, &oldSigStack);
         struct sigaction sa = { };
@@ -173,14 +158,18 @@
     bool FatalConditionHandler::isSet = false;
     struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {};
     stack_t FatalConditionHandler::oldSigStack = {};
-    char FatalConditionHandler::altStackMem[SIGSTKSZ] = {};
+    char FatalConditionHandler::altStackMem[sigStackSize] = {};
 
 
 } // namespace Catch
 
-#  endif // CATCH_CONFIG_POSIX_SIGNALS
+#else
 
-#endif // not Windows
+namespace Catch {
+    void FatalConditionHandler::reset() {}
+}
+
+#endif // signals/SEH handling
 
 #if defined(__GNUC__)
 #    pragma GCC diagnostic pop
diff --git a/include/internal/catch_fatal_condition.h b/include/internal/catch_fatal_condition.h
index 9977702..a64fa62 100644
--- a/include/internal/catch_fatal_condition.h
+++ b/include/internal/catch_fatal_condition.h
@@ -9,23 +9,12 @@
 #ifndef TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
 #define TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
 
-#include <string>
 #include "catch_platform.h"
 #include "catch_compiler_capabilities.h"
-
-
-#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
 #include "catch_windows_h_proxy.h"
 
-#  if !defined ( CATCH_CONFIG_WINDOWS_SEH )
 
-namespace Catch {
-    struct FatalConditionHandler {
-        void reset();
-    };
-}
-
-#  else // CATCH_CONFIG_WINDOWS_SEH is defined
+#if defined( CATCH_CONFIG_WINDOWS_SEH )
 
 namespace Catch {
 
@@ -44,20 +33,7 @@
 
 } // namespace Catch
 
-#  endif // CATCH_CONFIG_WINDOWS_SEH
-
-#else // Not Windows - assumed to be POSIX compatible //////////////////////////
-
-#  if !defined(CATCH_CONFIG_POSIX_SIGNALS)
-
-namespace Catch {
-    struct FatalConditionHandler {
-        void reset();
-    };
-}
-
-
-#  else // CATCH_CONFIG_POSIX_SIGNALS is defined
+#elif defined ( CATCH_CONFIG_POSIX_SIGNALS )
 
 #include <signal.h>
 
@@ -66,7 +42,7 @@
     struct FatalConditionHandler {
 
         static bool isSet;
-        static struct sigaction oldSigActions[];// [sizeof(signalDefs) / sizeof(SignalDefs)];
+        static struct sigaction oldSigActions[];
         static stack_t oldSigStack;
         static char altStackMem[];
 
@@ -79,8 +55,15 @@
 
 } // namespace Catch
 
-#  endif // CATCH_CONFIG_POSIX_SIGNALS
 
-#endif // not Windows
+#else
+
+namespace Catch {
+    struct FatalConditionHandler {
+        void reset();
+    };
+}
+
+#endif
 
 #endif // TWOBLUECUBES_CATCH_FATAL_CONDITION_H_INCLUDED
diff --git a/include/internal/catch_generators.cpp b/include/internal/catch_generators.cpp
new file mode 100644
index 0000000..5fbe2d2
--- /dev/null
+++ b/include/internal/catch_generators.cpp
@@ -0,0 +1,32 @@
+/*
+ *  Created by Phil Nash on 15/6/2018.
+ *
+ *  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 "catch_generators.hpp"
+#include "catch_random_number_generator.h"
+#include "catch_interfaces_capture.h"
+
+#include <limits>
+#include <set>
+
+namespace Catch {
+
+IGeneratorTracker::~IGeneratorTracker() {}
+
+const char* GeneratorException::what() const noexcept {
+    return m_msg;
+}
+
+namespace Generators {
+
+    GeneratorUntypedBase::~GeneratorUntypedBase() {}
+
+    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        return getResultCapture().acquireGeneratorTracker( lineInfo );
+    }
+
+} // namespace Generators
+} // namespace Catch
diff --git a/include/internal/catch_generators.hpp b/include/internal/catch_generators.hpp
new file mode 100644
index 0000000..40e434e
--- /dev/null
+++ b/include/internal/catch_generators.hpp
@@ -0,0 +1,207 @@
+/*
+ *  Created by Phil Nash on 15/6/2018.
+ *
+ *  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_CATCH_GENERATORS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include "catch_interfaces_generatortracker.h"
+#include "catch_common.h"
+#include "catch_enforce.h"
+
+#include <memory>
+#include <vector>
+#include <cassert>
+
+#include <utility>
+#include <exception>
+
+namespace Catch {
+
+class GeneratorException : public std::exception {
+    const char* const m_msg = "";
+
+public:
+    GeneratorException(const char* msg):
+        m_msg(msg)
+    {}
+
+    const char* what() const noexcept override final;
+};
+
+namespace Generators {
+
+    // !TBD move this into its own location?
+    namespace pf{
+        template<typename T, typename... Args>
+        std::unique_ptr<T> make_unique( Args&&... args ) {
+            return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+        }
+    }
+
+    template<typename T>
+    struct IGenerator : GeneratorUntypedBase {
+        virtual ~IGenerator() = default;
+
+        // Returns the current element of the generator
+        //
+        // \Precondition The generator is either freshly constructed,
+        // or the last call to `next()` returned true
+        virtual T const& get() const = 0;
+        using type = T;
+    };
+
+    template<typename T>
+    class SingleValueGenerator final : public IGenerator<T> {
+        T m_value;
+    public:
+        SingleValueGenerator(T const& value) : m_value( value ) {}
+        SingleValueGenerator(T&& value) : m_value(std::move(value)) {}
+
+        T const& get() const override {
+            return m_value;
+        }
+        bool next() override {
+            return false;
+        }
+    };
+
+    template<typename T>
+    class FixedValuesGenerator final : public IGenerator<T> {
+        std::vector<T> m_values;
+        size_t m_idx = 0;
+    public:
+        FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
+
+        T const& get() const override {
+            return m_values[m_idx];
+        }
+        bool next() override {
+            ++m_idx;
+            return m_idx < m_values.size();
+        }
+    };
+
+    template <typename T>
+    class GeneratorWrapper final {
+        std::unique_ptr<IGenerator<T>> m_generator;
+    public:
+        GeneratorWrapper(std::unique_ptr<IGenerator<T>> generator):
+            m_generator(std::move(generator))
+        {}
+        T const& get() const {
+            return m_generator->get();
+        }
+        bool next() {
+            return m_generator->next();
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> value(T&& value) {
+        return GeneratorWrapper<T>(pf::make_unique<SingleValueGenerator<T>>(std::forward<T>(value)));
+    }
+    template <typename T>
+    GeneratorWrapper<T> values(std::initializer_list<T> values) {
+        return GeneratorWrapper<T>(pf::make_unique<FixedValuesGenerator<T>>(values));
+    }
+
+    template<typename T>
+    class Generators : public IGenerator<T> {
+        std::vector<GeneratorWrapper<T>> m_generators;
+        size_t m_current = 0;
+
+        void populate(GeneratorWrapper<T>&& generator) {
+            m_generators.emplace_back(std::move(generator));
+        }
+        void populate(T&& val) {
+            m_generators.emplace_back(value(std::move(val)));
+        }
+        template<typename U>
+        void populate(U&& val) {
+            populate(T(std::move(val)));
+        }
+        template<typename U, typename... Gs>
+        void populate(U&& valueOrGenerator, Gs... moreGenerators) {
+            populate(std::forward<U>(valueOrGenerator));
+            populate(std::forward<Gs>(moreGenerators)...);
+        }
+
+    public:
+        template <typename... Gs>
+        Generators(Gs... moreGenerators) {
+            m_generators.reserve(sizeof...(Gs));
+            populate(std::forward<Gs>(moreGenerators)...);
+        }
+
+        T const& get() const override {
+            return m_generators[m_current].get();
+        }
+
+        bool next() override {
+            if (m_current >= m_generators.size()) {
+                return false;
+            }
+            const bool current_status = m_generators[m_current].next();
+            if (!current_status) {
+                ++m_current;
+            }
+            return m_current < m_generators.size();
+        }
+    };
+
+
+    template<typename... Ts>
+    GeneratorWrapper<std::tuple<Ts...>> table( std::initializer_list<std::tuple<typename std::decay<Ts>::type...>> tuples ) {
+        return values<std::tuple<Ts...>>( tuples );
+    }
+
+    // Tag type to signal that a generator sequence should convert arguments to a specific type
+    template <typename T>
+    struct as {};
+
+    template<typename T, typename... Gs>
+    auto makeGenerators( GeneratorWrapper<T>&& generator, Gs... moreGenerators ) -> Generators<T> {
+        return Generators<T>(std::move(generator), std::forward<Gs>(moreGenerators)...);
+    }
+    template<typename T>
+    auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
+        return Generators<T>(std::move(generator));
+    }
+    template<typename T, typename... Gs>
+    auto makeGenerators( T&& val, Gs... moreGenerators ) -> Generators<T> {
+        return makeGenerators( value( std::forward<T>( val ) ), std::forward<Gs>( moreGenerators )... );
+    }
+    template<typename T, typename U, typename... Gs>
+    auto makeGenerators( as<T>, U&& val, Gs... moreGenerators ) -> Generators<T> {
+        return makeGenerators( value( T( std::forward<U>( val ) ) ), std::forward<Gs>( moreGenerators )... );
+    }
+
+    auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&;
+
+    template<typename L>
+    // Note: The type after -> is weird, because VS2015 cannot parse
+    //       the expression used in the typedef inside, when it is in
+    //       return type. Yeah.
+    auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval<decltype(generatorExpression())>().get()) {
+        using UnderlyingType = typename decltype(generatorExpression())::type;
+
+        IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo );
+        if (!tracker.hasGenerator()) {
+            tracker.setGenerator(pf::make_unique<Generators<UnderlyingType>>(generatorExpression()));
+        }
+
+        auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker.getGenerator() );
+        return generator.get();
+    }
+
+} // namespace Generators
+} // namespace Catch
+
+#define GENERATE( ... ) \
+    Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, []{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } )
+
+
+#endif // TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
diff --git a/include/internal/catch_generators_generic.hpp b/include/internal/catch_generators_generic.hpp
new file mode 100644
index 0000000..2226dbc
--- /dev/null
+++ b/include/internal/catch_generators_generic.hpp
@@ -0,0 +1,230 @@
+/*
+ *  Created by Martin on 23/2/2019.
+ *
+ *  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_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
+
+#include "catch_generators.hpp"
+
+namespace Catch {
+namespace Generators {
+
+    template <typename T>
+    class TakeGenerator : public IGenerator<T> {
+        GeneratorWrapper<T> m_generator;
+        size_t m_returned = 0;
+        size_t m_target;
+    public:
+        TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_target(target)
+        {
+            assert(target != 0 && "Empty generators are not allowed");
+        }
+        T const& get() const override {
+            return m_generator.get();
+        }
+        bool next() override {
+            ++m_returned;
+            if (m_returned >= m_target) {
+                return false;
+            }
+
+            const auto success = m_generator.next();
+            // If the underlying generator does not contain enough values
+            // then we cut short as well
+            if (!success) {
+                m_returned = m_target;
+            }
+            return success;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(pf::make_unique<TakeGenerator<T>>(target, std::move(generator)));
+    }
+
+
+    template <typename T, typename Predicate>
+    class FilterGenerator : public IGenerator<T> {
+        GeneratorWrapper<T> m_generator;
+        Predicate m_predicate;
+    public:
+        template <typename P = Predicate>
+        FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_predicate(std::forward<P>(pred))
+        {
+            if (!m_predicate(m_generator.get())) {
+                // It might happen that there are no values that pass the
+                // filter. In that case we throw an exception.
+                auto has_initial_value = next();
+                if (!has_initial_value) {
+                    Catch::throw_exception(GeneratorException("No valid value found in filtered generator"));
+                }
+            }
+        }
+
+        T const& get() const override {
+            return m_generator.get();
+        }
+
+        bool next() override {
+            bool success = m_generator.next();
+            if (!success) {
+                return false;
+            }
+            while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
+            return success;
+        }
+    };
+
+
+    template <typename T, typename Predicate>
+    GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(std::unique_ptr<IGenerator<T>>(pf::make_unique<FilterGenerator<T, Predicate>>(std::forward<Predicate>(pred), std::move(generator))));
+    }
+
+    template <typename T>
+    class RepeatGenerator : public IGenerator<T> {
+        GeneratorWrapper<T> m_generator;
+        mutable std::vector<T> m_returned;
+        size_t m_target_repeats;
+        size_t m_current_repeat = 0;
+        size_t m_repeat_index = 0;
+    public:
+        RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
+            m_generator(std::move(generator)),
+            m_target_repeats(repeats)
+        {
+            assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
+        }
+
+        T const& get() const override {
+            if (m_current_repeat == 0) {
+                m_returned.push_back(m_generator.get());
+                return m_returned.back();
+            }
+            return m_returned[m_repeat_index];
+        }
+
+        bool next() override {
+            // There are 2 basic cases:
+            // 1) We are still reading the generator
+            // 2) We are reading our own cache
+
+            // In the first case, we need to poke the underlying generator.
+            // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
+            if (m_current_repeat == 0) {
+                const auto success = m_generator.next();
+                if (!success) {
+                    ++m_current_repeat;
+                }
+                return m_current_repeat < m_target_repeats;
+            }
+
+            // In the second case, we need to move indices forward and check that we haven't run up against the end
+            ++m_repeat_index;
+            if (m_repeat_index == m_returned.size()) {
+                m_repeat_index = 0;
+                ++m_current_repeat;
+            }
+            return m_current_repeat < m_target_repeats;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(pf::make_unique<RepeatGenerator<T>>(repeats, std::move(generator)));
+    }
+
+    template <typename T, typename U, typename Func>
+    class MapGenerator : public IGenerator<T> {
+        // TBD: provide static assert for mapping function, for friendly error message
+        GeneratorWrapper<U> m_generator;
+        Func m_function;
+        // To avoid returning dangling reference, we have to save the values
+        T m_cache;
+    public:
+        template <typename F2 = Func>
+        MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
+            m_generator(std::move(generator)),
+            m_function(std::forward<F2>(function)),
+            m_cache(m_function(m_generator.get()))
+        {}
+
+        T const& get() const override {
+            return m_cache;
+        }
+        bool next() override {
+            const auto success = m_generator.next();
+            if (success) {
+                m_cache = m_function(m_generator.get());
+            }
+            return success;
+        }
+    };
+
+    template <typename T, typename U, typename Func>
+    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
+        return GeneratorWrapper<T>(
+            pf::make_unique<MapGenerator<T, U, Func>>(std::forward<Func>(function), std::move(generator))
+        );
+    }
+    template <typename T, typename Func>
+    GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<T>(
+            pf::make_unique<MapGenerator<T, T, Func>>(std::forward<Func>(function), std::move(generator))
+        );
+    }
+
+    template <typename T>
+    class ChunkGenerator final : public IGenerator<std::vector<T>> {
+        std::vector<T> m_chunk;
+        size_t m_chunk_size;
+        GeneratorWrapper<T> m_generator;
+        bool m_used_up = false;
+    public:
+        ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
+            m_chunk_size(size), m_generator(std::move(generator))
+        {
+            m_chunk.reserve(m_chunk_size);
+            m_chunk.push_back(m_generator.get());
+            for (size_t i = 1; i < m_chunk_size; ++i) {
+                if (!m_generator.next()) {
+                    Catch::throw_exception(GeneratorException("Not enough values to initialize the first chunk"));
+                }
+                m_chunk.push_back(m_generator.get());
+            }
+        }
+        std::vector<T> const& get() const override {
+            return m_chunk;
+        }
+        bool next() override {
+            m_chunk.clear();
+            for (size_t idx = 0; idx < m_chunk_size; ++idx) {
+                if (!m_generator.next()) {
+                    return false;
+                }
+                m_chunk.push_back(m_generator.get());
+            }
+            return true;
+        }
+    };
+
+    template <typename T>
+    GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
+        return GeneratorWrapper<std::vector<T>>(
+            pf::make_unique<ChunkGenerator<T>>(size, std::move(generator))
+        );
+    }
+
+} // namespace Generators
+} // namespace Catch
+
+
+#endif // TWOBLUECUBES_CATCH_GENERATORS_GENERIC_HPP_INCLUDED
diff --git a/include/internal/catch_generators_specific.hpp b/include/internal/catch_generators_specific.hpp
new file mode 100644
index 0000000..7aae06b
--- /dev/null
+++ b/include/internal/catch_generators_specific.hpp
@@ -0,0 +1,135 @@
+/*
+ *  Created by Martin on 15/6/2018.
+ *
+ *  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_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
+
+#include "catch_context.h"
+#include "catch_generators.hpp"
+#include "catch_interfaces_config.h"
+
+#include <random>
+
+namespace Catch {
+namespace Generators {
+
+template <typename Float>
+class RandomFloatingGenerator final : public IGenerator<Float> {
+    // FIXME: What is the right seed?
+    std::minstd_rand m_rand;
+    std::uniform_real_distribution<Float> m_dist;
+    Float m_current_number;
+public:
+
+    RandomFloatingGenerator(Float a, Float b):
+        m_rand(getCurrentContext().getConfig()->rngSeed()),
+        m_dist(a, b) {
+        static_cast<void>(next());
+    }
+
+    Float const& get() const override {
+        return m_current_number;
+    }
+    bool next() override {
+        m_current_number = m_dist(m_rand);
+        return true;
+    }
+};
+
+template <typename Integer>
+class RandomIntegerGenerator final : public IGenerator<Integer> {
+    std::minstd_rand m_rand;
+    std::uniform_int_distribution<Integer> m_dist;
+    Integer m_current_number;
+public:
+
+    RandomIntegerGenerator(Integer a, Integer b):
+        m_rand(getCurrentContext().getConfig()->rngSeed()),
+        m_dist(a, b) {
+        static_cast<void>(next());
+    }
+
+    Integer const& get() const override {
+        return m_current_number;
+    }
+    bool next() override {
+        m_current_number = m_dist(m_rand);
+        return true;
+    }
+};
+
+// TODO: Ideally this would be also constrained against the various char types,
+//       but I don't expect users to run into that in practice.
+template <typename T>
+typename std::enable_if<std::is_integral<T>::value && !std::is_same<T, bool>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+    return GeneratorWrapper<T>(
+        pf::make_unique<RandomIntegerGenerator<T>>(a, b)
+    );
+}
+
+template <typename T>
+typename std::enable_if<std::is_floating_point<T>::value,
+GeneratorWrapper<T>>::type
+random(T a, T b) {
+    return GeneratorWrapper<T>(
+        pf::make_unique<RandomFloatingGenerator<T>>(a, b)
+    );
+}
+
+
+template <typename T>
+class RangeGenerator final : public IGenerator<T> {
+    T m_current;
+    T m_end;
+    T m_step;
+    bool m_positive;
+
+public:
+    RangeGenerator(T const& start, T const& end, T const& step):
+        m_current(start),
+        m_end(end),
+        m_step(step),
+        m_positive(m_step > T(0))
+    {
+        assert(m_current != m_end && "Range start and end cannot be equal");
+        assert(m_step != T(0) && "Step size cannot be zero");
+        assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
+    }
+
+    RangeGenerator(T const& start, T const& end):
+        RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
+    {}
+
+    T const& get() const override {
+        return m_current;
+    }
+
+    bool next() override {
+        m_current += m_step;
+        return (m_positive) ? (m_current < m_end) : (m_current > m_end);
+    }
+};
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
+    static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end, step));
+}
+
+template <typename T>
+GeneratorWrapper<T> range(T const& start, T const& end) {
+    static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
+    return GeneratorWrapper<T>(pf::make_unique<RangeGenerator<T>>(start, end));
+}
+
+
+} // namespace Generators
+} // namespace Catch
+
+
+#endif // TWOBLUECUBES_CATCH_GENERATORS_SPECIFIC_HPP_INCLUDED
diff --git a/include/internal/catch_interfaces_capture.h b/include/internal/catch_interfaces_capture.h
index 4d091f8..36f27a3 100644
--- a/include/internal/catch_interfaces_capture.h
+++ b/include/internal/catch_interfaces_capture.h
@@ -20,12 +20,15 @@
     struct SectionInfo;
     struct SectionEndInfo;
     struct MessageInfo;
+    struct MessageBuilder;
     struct Counts;
     struct BenchmarkInfo;
     struct BenchmarkStats;
     struct AssertionReaction;
+    struct SourceLineInfo;
 
     struct ITransientExpression;
+    struct IGeneratorTracker;
 
     struct IResultCapture {
 
@@ -36,12 +39,16 @@
         virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0;
         virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0;
 
+        virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0;
+
         virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
         virtual void benchmarkEnded( BenchmarkStats const& stats ) = 0;
 
         virtual void pushScopedMessage( MessageInfo const& message ) = 0;
         virtual void popScopedMessage( MessageInfo const& message ) = 0;
 
+        virtual void emplaceUnscopedMessage( MessageBuilder const& builder ) = 0;
+
         virtual void handleFatalErrorCondition( StringRef message ) = 0;
 
         virtual void handleExpr
diff --git a/include/internal/catch_interfaces_config.h b/include/internal/catch_interfaces_config.h
index 2584ccc..f509c7e 100644
--- a/include/internal/catch_interfaces_config.h
+++ b/include/internal/catch_interfaces_config.h
@@ -25,7 +25,8 @@
 
     struct WarnAbout { enum What {
         Nothing = 0x00,
-        NoAssertions = 0x01
+        NoAssertions = 0x01,
+        NoTests = 0x02
     }; };
 
     struct ShowDurations { enum OrNot {
@@ -62,10 +63,12 @@
         virtual bool includeSuccessfulResults() const = 0;
         virtual bool shouldDebugBreak() const = 0;
         virtual bool warnAboutMissingAssertions() const = 0;
+        virtual bool warnAboutNoTests() 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 bool hasTestFilters() const = 0;
         virtual RunTests::InWhatOrder runOrder() const = 0;
         virtual unsigned int rngSeed() const = 0;
         virtual int benchmarkResolutionMultiple() const = 0;
diff --git a/include/internal/catch_interfaces_exception.h b/include/internal/catch_interfaces_exception.h
index c803156..73ef990 100644
--- a/include/internal/catch_interfaces_exception.h
+++ b/include/internal/catch_interfaces_exception.h
@@ -8,7 +8,6 @@
 #ifndef TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
 #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
 
-#include "catch_capture.hpp"  // for CATCH_INTERNAL_TRY
 #include "catch_interfaces_registry_hub.h"
 
 #if defined(CATCH_CONFIG_DISABLE)
@@ -47,15 +46,17 @@
             {}
 
             std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
-                CATCH_INTERNAL_TRY {
+                CATCH_TRY {
                     if( it == itEnd )
                         std::rethrow_exception(std::current_exception());
                     else
                         return (*it)->translate( it+1, itEnd );
                 }
-                CATCH_INTERNAL_CATCH ( T&, ex ) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+                catch( T& ex ) {
                     return m_translateFunction( ex );
                 }
+#endif
             }
 
         protected:
diff --git a/include/internal/catch_interfaces_generatortracker.h b/include/internal/catch_interfaces_generatortracker.h
new file mode 100644
index 0000000..c1b1391
--- /dev/null
+++ b/include/internal/catch_interfaces_generatortracker.h
@@ -0,0 +1,39 @@
+/*
+ *  Created by Phil Nash on 26/6/2018.
+ *
+ *  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_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
+
+#include <memory>
+
+namespace Catch {
+
+    namespace Generators {
+        class GeneratorUntypedBase {
+        public:
+            GeneratorUntypedBase() = default;
+            virtual ~GeneratorUntypedBase();
+            // Attempts to move the generator to the next element
+             //
+             // Returns true iff the move succeeded (and a valid element
+             // can be retrieved).
+            virtual bool next() = 0;
+        };
+        using GeneratorBasePtr = std::unique_ptr<GeneratorUntypedBase>;
+
+    } // namespace Generators
+
+    struct IGeneratorTracker {
+        virtual ~IGeneratorTracker();
+        virtual auto hasGenerator() const -> bool = 0;
+        virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
+        virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
+    };
+
+} // namespace Catch
+
+#endif //TWOBLUECUBES_CATCH_INTERFACES_GENERATORTRACKER_INCLUDED
diff --git a/include/internal/catch_interfaces_registry_hub.h b/include/internal/catch_interfaces_registry_hub.h
index 1afbbec..8e1da61 100644
--- a/include/internal/catch_interfaces_registry_hub.h
+++ b/include/internal/catch_interfaces_registry_hub.h
@@ -33,7 +33,7 @@
         virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
         virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
 
-        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+        virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
 
 
         virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
@@ -49,7 +49,7 @@
         virtual void registerStartupException() noexcept = 0;
     };
 
-    IRegistryHub& getRegistryHub();
+    IRegistryHub const& getRegistryHub();
     IMutableRegistryHub& getMutableRegistryHub();
     void cleanUp();
     std::string translateActiveException();
diff --git a/include/internal/catch_interfaces_reporter.cpp b/include/internal/catch_interfaces_reporter.cpp
index 129a5f4..0c367c5 100644
--- a/include/internal/catch_interfaces_reporter.cpp
+++ b/include/internal/catch_interfaces_reporter.cpp
@@ -6,7 +6,7 @@
  */
 
 #include "catch_interfaces_reporter.h"
-#include "../reporters/catch_reporter_multi.h"
+#include "../reporters/catch_reporter_listening.h"
 
 namespace Catch {
 
@@ -111,25 +111,4 @@
     IReporterFactory::~IReporterFactory() = default;
     IReporterRegistry::~IReporterRegistry() = default;
 
-    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter ) {
-
-        if( !existingReporter ) {
-            existingReporter = std::move( additionalReporter );
-            return;
-        }
-
-        MultipleReporters* multi = nullptr;
-
-        if( existingReporter->isMulti() ) {
-            multi = static_cast<MultipleReporters*>( existingReporter.get() );
-        }
-        else {
-            auto newMulti = std::unique_ptr<MultipleReporters>( new MultipleReporters );
-            newMulti->add( std::move( existingReporter ) );
-            multi = newMulti.get();
-            existingReporter = std::move( newMulti );
-        }
-        multi->add( std::move( additionalReporter ) );
-    }
-
 } // end namespace Catch
diff --git a/include/internal/catch_interfaces_reporter.h b/include/internal/catch_interfaces_reporter.h
index b620abb..e5fbf8b 100644
--- a/include/internal/catch_interfaces_reporter.h
+++ b/include/internal/catch_interfaces_reporter.h
@@ -42,6 +42,7 @@
 
     struct ReporterPreferences {
         bool shouldRedirectStdOut = false;
+        bool shouldReportAllAssertions = false;
     };
 
     template<typename T>
@@ -79,8 +80,8 @@
 
         AssertionStats( AssertionStats const& )              = default;
         AssertionStats( AssertionStats && )                  = default;
-        AssertionStats& operator = ( AssertionStats const& ) = default;
-        AssertionStats& operator = ( AssertionStats && )     = default;
+        AssertionStats& operator = ( AssertionStats const& ) = delete;
+        AssertionStats& operator = ( AssertionStats && )     = delete;
         virtual ~AssertionStats();
 
         AssertionResult assertionResult;
@@ -226,8 +227,6 @@
         virtual Listeners const& getListeners() const = 0;
     };
 
-    void addReporter( IStreamingReporterPtr& existingReporter, IStreamingReporterPtr&& additionalReporter );
-
 } // end namespace Catch
 
 #endif // TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
diff --git a/include/internal/catch_interfaces_testcase.h b/include/internal/catch_interfaces_testcase.h
index 9e02b14..f57cc8f 100644
--- a/include/internal/catch_interfaces_testcase.h
+++ b/include/internal/catch_interfaces_testcase.h
@@ -9,7 +9,6 @@
 #define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
 
 #include <vector>
-#include <memory>
 
 namespace Catch {
 
@@ -20,8 +19,6 @@
         virtual ~ITestInvoker();
     };
 
-    using ITestCasePtr = std::shared_ptr<ITestInvoker>;
-
     class TestCase;
     struct IConfig;
 
diff --git a/include/internal/catch_leak_detector.cpp b/include/internal/catch_leak_detector.cpp
index 36aba6a..7a30e8a 100644
--- a/include/internal/catch_leak_detector.cpp
+++ b/include/internal/catch_leak_detector.cpp
@@ -6,6 +6,7 @@
  */
 
  #include "catch_leak_detector.h"
+ #include "catch_interfaces_registry_hub.h"
 
 
 #ifdef CATCH_CONFIG_WINDOWS_CRTDBG
@@ -13,16 +14,16 @@
 
 namespace Catch {
 
-	LeakDetector::LeakDetector() {
-		int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
-		flag |= _CRTDBG_LEAK_CHECK_DF;
-		flag |= _CRTDBG_ALLOC_MEM_DF;
-		_CrtSetDbgFlag(flag);
-		_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
-		_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
-		// Change this to leaking allocation's number to break there
-		_CrtSetBreakAlloc(-1);
-	}
+    LeakDetector::LeakDetector() {
+        int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
+        flag |= _CRTDBG_LEAK_CHECK_DF;
+        flag |= _CRTDBG_ALLOC_MEM_DF;
+        _CrtSetDbgFlag(flag);
+        _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+        _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+        // Change this to leaking allocation's number to break there
+        _CrtSetBreakAlloc(-1);
+    }
 }
 
 #else
@@ -30,3 +31,7 @@
     Catch::LeakDetector::LeakDetector() {}
 
 #endif
+
+Catch::LeakDetector::~LeakDetector() {
+    Catch::cleanUp();
+}
diff --git a/include/internal/catch_leak_detector.h b/include/internal/catch_leak_detector.h
index bfb0b42..633457a 100644
--- a/include/internal/catch_leak_detector.h
+++ b/include/internal/catch_leak_detector.h
@@ -11,6 +11,7 @@
 
     struct LeakDetector {
         LeakDetector();
+        ~LeakDetector();
     };
 
 }
diff --git a/include/internal/catch_list.cpp b/include/internal/catch_list.cpp
index 3efad0b..e1d9922 100644
--- a/include/internal/catch_list.cpp
+++ b/include/internal/catch_list.cpp
@@ -12,6 +12,7 @@
 #include "catch_interfaces_reporter.h"
 #include "catch_interfaces_testcase.h"
 
+#include "catch_context.h"
 #include "catch_stream.h"
 #include "catch_text.h"
 
@@ -28,11 +29,10 @@
 
     std::size_t listTests( Config const& config ) {
         TestSpec testSpec = config.testSpec();
-        if( config.testSpec().hasFilters() )
+        if( config.hasTestFilters() )
             Catch::cout() << "Matching test cases:\n";
         else {
             Catch::cout() << "All available test cases:\n";
-            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
         }
 
         auto matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config );
@@ -54,7 +54,7 @@
                 Catch::cout() << Column( testCaseInfo.tagsAsString() ).indent( 6 ) << "\n";
         }
 
-        if( !config.testSpec().hasFilters() )
+        if( !config.hasTestFilters() )
             Catch::cout() << pluralise( matchedTestCases.size(), "test case" ) << '\n' << std::endl;
         else
             Catch::cout() << pluralise( matchedTestCases.size(), "matching test case" ) << '\n' << std::endl;
@@ -63,8 +63,6 @@
 
     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( auto const& testCaseInfo : matchedTestCases ) {
@@ -94,11 +92,10 @@
 
     std::size_t listTags( Config const& config ) {
         TestSpec testSpec = config.testSpec();
-        if( config.testSpec().hasFilters() )
+        if( config.hasTestFilters() )
             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;
@@ -128,7 +125,7 @@
         return tagCounts.size();
     }
 
-    std::size_t listReporters( Config const& /*config*/ ) {
+    std::size_t listReporters() {
         Catch::cout() << "Available reporters:\n";
         IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
         std::size_t maxNameLen = 0;
@@ -150,16 +147,17 @@
         return factories.size();
     }
 
-    Option<std::size_t> list( Config const& config ) {
+    Option<std::size_t> list( std::shared_ptr<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 );
+        getCurrentMutableContext().setConfig( config );
+        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();
         return listedCount;
     }
 
diff --git a/include/internal/catch_list.h b/include/internal/catch_list.h
index 4bc96ec..cea7bba 100644
--- a/include/internal/catch_list.h
+++ b/include/internal/catch_list.h
@@ -29,9 +29,9 @@
 
     std::size_t listTags( Config const& config );
 
-    std::size_t listReporters( Config const& /*config*/ );
+    std::size_t listReporters();
     
-    Option<std::size_t> list( Config const& config );
+    Option<std::size_t> list( std::shared_ptr<Config> const& config );
 
 } // end namespace Catch
 
diff --git a/include/internal/catch_matchers.h b/include/internal/catch_matchers.h
index cacdeb3..aebd4c2 100644
--- a/include/internal/catch_matchers.h
+++ b/include/internal/catch_matchers.h
@@ -38,18 +38,11 @@
 #    pragma clang diagnostic push
 #    pragma clang diagnostic ignored "-Wnon-virtual-dtor"
 #endif
-/*
- * include/internal/catch_matchers.h:38:16: error: 'Catch::Matchers::Impl::MatcherMethod<std::__1::basic_string<char> >' has virtual functions but non-virtual destructor [-Werror,-Wnon-virtual-dtor]
- */
 
         template<typename ObjectT>
         struct MatcherMethod {
             virtual bool match( ObjectT const& arg ) const = 0;
         };
-        template<typename PtrT>
-        struct MatcherMethod<PtrT*> {
-            virtual bool match( PtrT* arg ) const = 0;
-        };
 
 #ifdef __clang__
 #    pragma clang diagnostic pop
diff --git a/include/internal/catch_matchers_floating.cpp b/include/internal/catch_matchers_floating.cpp
index e9abeb9..9bc082e 100644
--- a/include/internal/catch_matchers_floating.cpp
+++ b/include/internal/catch_matchers_floating.cpp
@@ -6,12 +6,14 @@
  */
 
 #include "catch_matchers_floating.h"
+#include "catch_enforce.h"
+#include "catch_polyfills.hpp"
+#include "catch_to_string.hpp"
 #include "catch_tostring.h"
 
 #include <cstdlib>
 #include <cstdint>
 #include <cstring>
-#include <stdexcept>
 
 namespace Catch {
 namespace Matchers {
@@ -56,7 +58,7 @@
 bool almostEqualUlps(FP lhs, FP rhs, int maxUlpDiff) {
     // Comparison with NaN should always be false.
     // This way we can rule it out before getting into the ugly details
-    if (std::isnan(lhs) || std::isnan(rhs)) {
+    if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
         return false;
     }
 
@@ -80,15 +82,14 @@
 namespace Floating {
     WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
         :m_target{ target }, m_margin{ margin } {
-        if (m_margin < 0) {
-          Exception::doThrow( std::domain_error("Allowed margin difference has to be >= 0") );
-        }
+        CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
+            << " Margin has to be non-negative.");
     }
 
     // Performs equivalent check of std::fabs(lhs - rhs) <= margin
     // But without the subtraction to allow for INFINITY in comparison
     bool WithinAbsMatcher::match(double const& matchee) const {
-        return (matchee + m_margin >= m_target) && (m_target + m_margin >= m_margin);
+        return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
     }
 
     std::string WithinAbsMatcher::describe() const {
@@ -98,11 +99,16 @@
 
     WithinUlpsMatcher::WithinUlpsMatcher(double target, int ulps, FloatingPointKind baseType)
         :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
-        if (m_ulps < 0) {
-          Exception::doThrow( std::domain_error("Allowed ulp difference has to be >= 0") );
-        }
+        CATCH_ENFORCE(ulps >= 0, "Invalid ULP setting: " << ulps << '.'
+            << " ULPs have to be non-negative.");
     }
 
+#if defined(__clang__)
+#pragma clang diagnostic push
+// Clang <3.5 reports on the default branch in the switch below
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+
     bool WithinUlpsMatcher::match(double const& matchee) const {
         switch (m_type) {
         case FloatingPointKind::Float:
@@ -110,12 +116,16 @@
         case FloatingPointKind::Double:
             return almostEqualUlps<double>(matchee, m_target, m_ulps);
         default:
-            Exception::doThrow( std::domain_error("Unknown FloatingPointKind value") );
+            CATCH_INTERNAL_ERROR( "Unknown FloatingPointKind value" );
         }
     }
 
+#if defined(__clang__)
+#pragma clang diagnostic pop
+#endif
+
     std::string WithinUlpsMatcher::describe() const {
-        return "is within " + std::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
+        return "is within " + Catch::to_string(m_ulps) + " ULPs of " + ::Catch::Detail::stringify(m_target) + ((m_type == FloatingPointKind::Float)? "f" : "");
     }
 
 }// namespace Floating
diff --git a/include/internal/catch_matchers_generic.cpp b/include/internal/catch_matchers_generic.cpp
new file mode 100644
index 0000000..300102e
--- /dev/null
+++ b/include/internal/catch_matchers_generic.cpp
@@ -0,0 +1,9 @@
+#include "catch_matchers_generic.hpp"
+
+std::string Catch::Matchers::Generic::Detail::finalizeDescription(const std::string& desc) {
+    if (desc.empty()) {
+        return "matches undescribed predicate";
+    } else {
+        return "matches predicate: \"" + desc + '"';
+    }
+}
diff --git a/include/internal/catch_matchers_generic.hpp b/include/internal/catch_matchers_generic.hpp
new file mode 100644
index 0000000..7c4f9f1
--- /dev/null
+++ b/include/internal/catch_matchers_generic.hpp
@@ -0,0 +1,58 @@
+/*
+ *  Created by Martin Hořeňovský on 03/04/2017.
+ *
+ * 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_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
+
+#include "catch_common.h"
+#include "catch_matchers.h"
+
+#include <functional>
+#include <string>
+
+namespace Catch {
+namespace Matchers {
+namespace Generic {
+
+namespace Detail {
+    std::string finalizeDescription(const std::string& desc);
+}
+
+template <typename T>
+class PredicateMatcher : public MatcherBase<T> {
+    std::function<bool(T const&)> m_predicate;
+    std::string m_description;
+public:
+
+    PredicateMatcher(std::function<bool(T const&)> const& elem, std::string const& descr)
+        :m_predicate(std::move(elem)),
+        m_description(Detail::finalizeDescription(descr))
+    {}
+
+    bool match( T const& item ) const override {
+        return m_predicate(item);
+    }
+
+    std::string describe() const override {
+        return m_description;
+    }
+};
+
+} // namespace Generic
+
+    // The following functions create the actual matcher objects.
+    // The user has to explicitly specify type to the function, because
+    // infering std::function<bool(T const&)> is hard (but possible) and
+    // requires a lot of TMP.
+    template<typename T>
+    Generic::PredicateMatcher<T> Predicate(std::function<bool(T const&)> const& predicate, std::string const& description = "") {
+        return Generic::PredicateMatcher<T>(predicate, description);
+    }
+
+} // namespace Matchers
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_MATCHERS_GENERIC_HPP_INCLUDED
diff --git a/include/internal/catch_matchers_vector.h b/include/internal/catch_matchers_vector.h
index 833d7dc..1e29cc9 100644
--- a/include/internal/catch_matchers_vector.h
+++ b/include/internal/catch_matchers_vector.h
@@ -124,7 +124,7 @@
                 auto lfirst = m_target.begin(), llast = m_target.end();
                 auto rfirst = vec.begin(), rlast = vec.end();
                 // Cut common prefix to optimize checking of permuted parts
-                while (lfirst != llast && *lfirst != *rfirst) {
+                while (lfirst != llast && *lfirst == *rfirst) {
                     ++lfirst; ++rfirst;
                 }
                 if (lfirst == llast) {
diff --git a/include/internal/catch_message.cpp b/include/internal/catch_message.cpp
index 8684970..fa7e874 100644
--- a/include/internal/catch_message.cpp
+++ b/include/internal/catch_message.cpp
@@ -10,9 +10,12 @@
 #include "catch_interfaces_capture.h"
 #include "catch_uncaught_exceptions.h"
 
+#include <cassert>
+#include <stack>
+
 namespace Catch {
 
-    MessageInfo::MessageInfo(   std::string const& _macroName,
+    MessageInfo::MessageInfo(   StringRef const& _macroName,
                                 SourceLineInfo const& _lineInfo,
                                 ResultWas::OfType _type )
     :   macroName( _macroName ),
@@ -35,7 +38,7 @@
 
     ////////////////////////////////////////////////////////////////////////////
 
-    Catch::MessageBuilder::MessageBuilder( std::string const& macroName,
+    Catch::MessageBuilder::MessageBuilder( StringRef const& macroName,
                                            SourceLineInfo const& lineInfo,
                                            ResultWas::OfType type )
         :m_info(macroName, lineInfo, type) {}
@@ -44,15 +47,82 @@
 
 
     ScopedMessage::ScopedMessage( MessageBuilder const& builder )
-    : m_info( builder.m_info )
+    : m_info( builder.m_info ), m_moved()
     {
         m_info.message = builder.m_stream.str();
         getResultCapture().pushScopedMessage( m_info );
     }
 
+    ScopedMessage::ScopedMessage( ScopedMessage&& old )
+    : m_info( old.m_info ), m_moved()
+    {
+        old.m_moved = true;
+    }
+
     ScopedMessage::~ScopedMessage() {
-        if ( !uncaught_exceptions() ){
+        if ( !uncaught_exceptions() && !m_moved ){
             getResultCapture().popScopedMessage(m_info);
         }
     }
+
+
+    Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) {
+        auto trimmed = [&] (size_t start, size_t end) {
+            while (names[start] == ',' || isspace(names[start])) {
+                ++start;
+            }
+            while (names[end] == ',' || isspace(names[end])) {
+                --end;
+            }
+            return names.substr(start, end - start + 1);
+        };
+
+        size_t start = 0;
+        std::stack<char> openings;
+        for (size_t pos = 0; pos < names.size(); ++pos) {
+            char c = names[pos];
+            switch (c) {
+            case '[':
+            case '{':
+            case '(':
+            // It is basically impossible to disambiguate between
+            // comparison and start of template args in this context
+//            case '<':
+                openings.push(c);
+                break;
+            case ']':
+            case '}':
+            case ')':
+//           case '>':
+                openings.pop();
+                break;
+            case ',':
+                if (start != pos && openings.size() == 0) {
+                    m_messages.emplace_back(macroName, lineInfo, resultType);
+                    m_messages.back().message = trimmed(start, pos);
+                    m_messages.back().message += " := ";
+                    start = pos;
+                }
+            }
+        }
+        assert(openings.size() == 0 && "Mismatched openings");
+        m_messages.emplace_back(macroName, lineInfo, resultType);
+        m_messages.back().message = trimmed(start, names.size() - 1);
+        m_messages.back().message += " := ";
+    }
+    Capturer::~Capturer() {
+        if ( !uncaught_exceptions() ){
+            assert( m_captured == m_messages.size() );
+            for( size_t i = 0; i < m_captured; ++i  )
+                m_resultCapture.popScopedMessage( m_messages[i] );
+        }
+    }
+
+    void Capturer::captureValue( size_t index, std::string const& value ) {
+        assert( index < m_messages.size() );
+        m_messages[index].message += value;
+        m_resultCapture.pushScopedMessage( m_messages[index] );
+        m_captured++;
+    }
+
 } // end namespace Catch
diff --git a/include/internal/catch_message.h b/include/internal/catch_message.h
index 0a512ed..748f5ac 100644
--- a/include/internal/catch_message.h
+++ b/include/internal/catch_message.h
@@ -8,19 +8,23 @@
 #ifndef TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
 #define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
 
-#include <string>
 #include "catch_result_type.h"
 #include "catch_common.h"
 #include "catch_stream.h"
+#include "catch_interfaces_capture.h"
+#include "catch_tostring.h"
+
+#include <string>
+#include <vector>
 
 namespace Catch {
 
     struct MessageInfo {
-        MessageInfo(    std::string const& _macroName,
+        MessageInfo(    StringRef const& _macroName,
                         SourceLineInfo const& _lineInfo,
                         ResultWas::OfType _type );
 
-        std::string macroName;
+        StringRef macroName;
         std::string message;
         SourceLineInfo lineInfo;
         ResultWas::OfType type;
@@ -44,7 +48,7 @@
     };
 
     struct MessageBuilder : MessageStream {
-        MessageBuilder( std::string const& macroName,
+        MessageBuilder( StringRef const& macroName,
                         SourceLineInfo const& lineInfo,
                         ResultWas::OfType type );
 
@@ -60,9 +64,34 @@
     class ScopedMessage {
     public:
         explicit ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage& duplicate ) = delete;
+        ScopedMessage( ScopedMessage&& old );
         ~ScopedMessage();
 
         MessageInfo m_info;
+        bool m_moved;
+    };
+
+    class Capturer {
+        std::vector<MessageInfo> m_messages;
+        IResultCapture& m_resultCapture = getResultCapture();
+        size_t m_captured = 0;
+    public:
+        Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
+        ~Capturer();
+
+        void captureValue( size_t index, std::string const& value );
+
+        template<typename T>
+        void captureValues( size_t index, T const& value ) {
+            captureValue( index, Catch::Detail::stringify( value ) );
+        }
+
+        template<typename T, typename... Ts>
+        void captureValues( size_t index, T const& value, Ts const&... values ) {
+            captureValue( index, Catch::Detail::stringify(value) );
+            captureValues( index+1, values... );
+        }
     };
 
 } // end namespace Catch
diff --git a/include/internal/catch_meta.hpp b/include/internal/catch_meta.hpp
new file mode 100644
index 0000000..3508a46
--- /dev/null
+++ b/include/internal/catch_meta.hpp
@@ -0,0 +1,77 @@
+/*
+ *  Created by Jozef on 02/12/2018.
+ *  Copyright 2018 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_CATCH_META_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_META_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch {
+template< typename... >
+struct TypeList {};
+
+template< typename... >
+struct append;
+
+template< template<typename...> class L1
+    , typename...E1
+    , template<typename...> class L2
+    , typename...E2
+>
+struct append< L1<E1...>, L2<E2...> > {
+    using type = L1<E1..., E2...>;
+};
+
+template< template<typename...> class L1
+    , typename...E1
+    , template<typename...> class L2
+    , typename...E2
+    , typename...Rest
+>
+struct append< L1<E1...>, L2<E2...>, Rest...> {
+    using type = typename append< L1<E1..., E2...>, Rest... >::type;
+};
+
+template< template<typename...> class
+    , typename...
+>
+struct rewrap;
+
+template< template<typename...> class Container
+    , template<typename...> class List
+    , typename...elems
+>
+struct rewrap<Container, List<elems...>> {
+    using type = TypeList< Container< elems... > >;
+};
+
+template< template<typename...> class Container
+    , template<typename...> class List
+    , class...Elems
+    , typename...Elements>
+    struct rewrap<Container, List<Elems...>, Elements...> {
+    using type = typename append<TypeList<Container<Elems...>>, typename rewrap<Container, Elements...>::type>::type;
+};
+
+template< template<typename...> class...Containers >
+struct combine {
+    template< typename...Types >
+    struct with_types {
+        template< template <typename...> class Final >
+        struct into {
+            using type = typename append<Final<>, typename rewrap<Containers, Types...>::type...>::type;
+        };
+    };
+};
+
+template<typename T>
+struct always_false : std::false_type {};
+
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_META_HPP_INCLUDED
diff --git a/include/internal/catch_objc.hpp b/include/internal/catch_objc.hpp
index b43f335..39cbb1f 100644
--- a/include/internal/catch_objc.hpp
+++ b/include/internal/catch_objc.hpp
@@ -93,7 +93,7 @@
                         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("",0) ) );
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, NameAndTags( name.c_str(), desc.c_str() ), SourceLineInfo("",0) ) );
                         noTestMethods++;
                     }
                 }
diff --git a/include/internal/catch_output_redirect.cpp b/include/internal/catch_output_redirect.cpp
new file mode 100644
index 0000000..a0a9aff
--- /dev/null
+++ b/include/internal/catch_output_redirect.cpp
@@ -0,0 +1,147 @@
+/*
+ *  Created by Martin on 28/04/2018.
+ *
+ *  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 "catch_output_redirect.h"
+#include "catch_enforce.h"
+
+#include <cstdio>
+#include <cstring>
+#include <fstream>
+#include <sstream>
+#include <stdexcept>
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+    #if defined(_MSC_VER)
+    #include <io.h>      //_dup and _dup2
+    #define dup _dup
+    #define dup2 _dup2
+    #define fileno _fileno
+    #else
+    #include <unistd.h>  // dup and dup2
+    #endif
+#endif
+
+
+namespace Catch {
+
+    RedirectedStream::RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
+    :   m_originalStream( originalStream ),
+        m_redirectionStream( redirectionStream ),
+        m_prevBuf( m_originalStream.rdbuf() )
+    {
+        m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
+    }
+
+    RedirectedStream::~RedirectedStream() {
+        m_originalStream.rdbuf( m_prevBuf );
+    }
+
+    RedirectedStdOut::RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
+    auto RedirectedStdOut::str() const -> std::string { return m_rss.str(); }
+
+    RedirectedStdErr::RedirectedStdErr()
+    :   m_cerr( Catch::cerr(), m_rss.get() ),
+        m_clog( Catch::clog(), m_rss.get() )
+    {}
+    auto RedirectedStdErr::str() const -> std::string { return m_rss.str(); }
+
+    RedirectedStreams::RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr)
+    :   m_redirectedCout(redirectedCout),
+        m_redirectedCerr(redirectedCerr)
+    {}
+
+    RedirectedStreams::~RedirectedStreams() {
+        m_redirectedCout += m_redirectedStdOut.str();
+        m_redirectedCerr += m_redirectedStdErr.str();
+    }
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+#if defined(_MSC_VER)
+    TempFile::TempFile() {
+        if (tmpnam_s(m_buffer)) {
+            CATCH_RUNTIME_ERROR("Could not get a temp filename");
+        }
+        if (fopen_s(&m_file, m_buffer, "w")) {
+            char buffer[100];
+            if (strerror_s(buffer, errno)) {
+                CATCH_RUNTIME_ERROR("Could not translate errno to a string");
+            }
+            CATCH_RUNTIME_ERROR("Coul dnot open the temp file: '" << m_buffer << "' because: " << buffer);
+        }
+    }
+#else
+    TempFile::TempFile() {
+        m_file = std::tmpfile();
+        if (!m_file) {
+            CATCH_RUNTIME_ERROR("Could not create a temp file.");
+        }
+    }
+
+#endif
+
+    TempFile::~TempFile() {
+         // TBD: What to do about errors here?
+         std::fclose(m_file);
+         // We manually create the file on Windows only, on Linux
+         // it will be autodeleted
+#if defined(_MSC_VER)
+         std::remove(m_buffer);
+#endif
+    }
+
+
+    FILE* TempFile::getFile() {
+        return m_file;
+    }
+
+    std::string TempFile::getContents() {
+        std::stringstream sstr;
+        char buffer[100] = {};
+        std::rewind(m_file);
+        while (std::fgets(buffer, sizeof(buffer), m_file)) {
+            sstr << buffer;
+        }
+        return sstr.str();
+    }
+
+    OutputRedirect::OutputRedirect(std::string& stdout_dest, std::string& stderr_dest) :
+        m_originalStdout(dup(1)),
+        m_originalStderr(dup(2)),
+        m_stdoutDest(stdout_dest),
+        m_stderrDest(stderr_dest) {
+        dup2(fileno(m_stdoutFile.getFile()), 1);
+        dup2(fileno(m_stderrFile.getFile()), 2);
+    }
+
+    OutputRedirect::~OutputRedirect() {
+        Catch::cout() << std::flush;
+        fflush(stdout);
+        // Since we support overriding these streams, we flush cerr
+        // even though std::cerr is unbuffered
+        Catch::cerr() << std::flush;
+        Catch::clog() << std::flush;
+        fflush(stderr);
+
+        dup2(m_originalStdout, 1);
+        dup2(m_originalStderr, 2);
+
+        m_stdoutDest += m_stdoutFile.getContents();
+        m_stderrDest += m_stderrFile.getContents();
+    }
+
+#endif // CATCH_CONFIG_NEW_CAPTURE
+
+} // namespace Catch
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+    #if defined(_MSC_VER)
+    #undef dup
+    #undef dup2
+    #undef fileno
+    #endif
+#endif
diff --git a/include/internal/catch_output_redirect.h b/include/internal/catch_output_redirect.h
new file mode 100644
index 0000000..3d1c2d4
--- /dev/null
+++ b/include/internal/catch_output_redirect.h
@@ -0,0 +1,116 @@
+/*
+ *  Created by Martin on 28/04/2018.
+ *
+ *  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_CATCH_OUTPUT_REDIRECT_H
+#define TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
+
+#include "catch_platform.h"
+#include "catch_stream.h"
+
+#include <cstdio>
+#include <iosfwd>
+#include <string>
+
+namespace Catch {
+
+    class RedirectedStream {
+        std::ostream& m_originalStream;
+        std::ostream& m_redirectionStream;
+        std::streambuf* m_prevBuf;
+
+    public:
+        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream );
+        ~RedirectedStream();
+    };
+
+    class RedirectedStdOut {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cout;
+    public:
+        RedirectedStdOut();
+        auto str() const -> std::string;
+    };
+
+    // StdErr has two constituent streams in C++, std::cerr and std::clog
+    // This means that we need to redirect 2 streams into 1 to keep proper
+    // order of writes
+    class RedirectedStdErr {
+        ReusableStringStream m_rss;
+        RedirectedStream m_cerr;
+        RedirectedStream m_clog;
+    public:
+        RedirectedStdErr();
+        auto str() const -> std::string;
+    };
+
+    class RedirectedStreams {
+    public:
+        RedirectedStreams(RedirectedStreams const&) = delete;
+        RedirectedStreams& operator=(RedirectedStreams const&) = delete;
+        RedirectedStreams(RedirectedStreams&&) = delete;
+        RedirectedStreams& operator=(RedirectedStreams&&) = delete;
+
+        RedirectedStreams(std::string& redirectedCout, std::string& redirectedCerr);
+        ~RedirectedStreams();
+    private:
+        std::string& m_redirectedCout;
+        std::string& m_redirectedCerr;
+        RedirectedStdOut m_redirectedStdOut;
+        RedirectedStdErr m_redirectedStdErr;
+    };
+
+#if defined(CATCH_CONFIG_NEW_CAPTURE)
+
+    // Windows's implementation of std::tmpfile is terrible (it tries
+    // to create a file inside system folder, thus requiring elevated
+    // privileges for the binary), so we have to use tmpnam(_s) and
+    // create the file ourselves there.
+    class TempFile {
+    public:
+        TempFile(TempFile const&) = delete;
+        TempFile& operator=(TempFile const&) = delete;
+        TempFile(TempFile&&) = delete;
+        TempFile& operator=(TempFile&&) = delete;
+
+        TempFile();
+        ~TempFile();
+
+        std::FILE* getFile();
+        std::string getContents();
+
+    private:
+        std::FILE* m_file = nullptr;
+    #if defined(_MSC_VER)
+        char m_buffer[L_tmpnam] = { 0 };
+    #endif
+    };
+
+
+    class OutputRedirect {
+    public:
+        OutputRedirect(OutputRedirect const&) = delete;
+        OutputRedirect& operator=(OutputRedirect const&) = delete;
+        OutputRedirect(OutputRedirect&&) = delete;
+        OutputRedirect& operator=(OutputRedirect&&) = delete;
+
+
+        OutputRedirect(std::string& stdout_dest, std::string& stderr_dest);
+        ~OutputRedirect();
+
+    private:
+        int m_originalStdout = -1;
+        int m_originalStderr = -1;
+        TempFile m_stdoutFile;
+        TempFile m_stderrFile;
+        std::string& m_stdoutDest;
+        std::string& m_stderrDest;
+    };
+
+#endif
+
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_OUTPUT_REDIRECT_H
diff --git a/include/internal/catch_platform.h b/include/internal/catch_platform.h
index cbf1792..e14cd33 100644
--- a/include/internal/catch_platform.h
+++ b/include/internal/catch_platform.h
@@ -20,7 +20,7 @@
 #elif defined(linux) || defined(__linux) || defined(__linux__)
 #  define CATCH_PLATFORM_LINUX
 
-#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
 #  define CATCH_PLATFORM_WINDOWS
 #endif
 
diff --git a/include/internal/catch_polyfills.cpp b/include/internal/catch_polyfills.cpp
new file mode 100644
index 0000000..68a2c82
--- /dev/null
+++ b/include/internal/catch_polyfills.cpp
@@ -0,0 +1,31 @@
+/*
+ *  Created by Martin on 17/11/2017.
+ *
+ *  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 "catch_polyfills.hpp"
+
+#include <cmath>
+
+namespace Catch {
+
+#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
+    bool isnan(float f) {
+        return std::isnan(f);
+    }
+    bool isnan(double d) {
+        return std::isnan(d);
+    }
+#else
+    // For now we only use this for embarcadero
+    bool isnan(float f) {
+        return std::_isnan(f);
+    }
+    bool isnan(double d) {
+        return std::_isnan(d);
+    }
+#endif
+
+} // end namespace Catch
diff --git a/include/internal/catch_polyfills.hpp b/include/internal/catch_polyfills.hpp
new file mode 100644
index 0000000..ba4189e
--- /dev/null
+++ b/include/internal/catch_polyfills.hpp
@@ -0,0 +1,15 @@
+/*
+ *  Created by Martin on 17/11/2017.
+ *
+ *  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_CATCH_POLYFILLS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_POLYFILLS_HPP_INCLUDED
+
+namespace Catch {
+    bool isnan(float f);
+    bool isnan(double d);
+}
+
+#endif // TWOBLUECUBES_CATCH_POLYFILLS_HPP_INCLUDED
diff --git a/include/internal/catch_preprocessor.hpp b/include/internal/catch_preprocessor.hpp
new file mode 100644
index 0000000..faf41e6
--- /dev/null
+++ b/include/internal/catch_preprocessor.hpp
@@ -0,0 +1,89 @@
+/*
+ *  Created by Jozef on 12/11/2018.
+ *  Copyright 2017 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_CATCH_PREPROCESSOR_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED
+
+#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
+#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
+#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
+
+#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
+// MSVC needs more evaluations
+#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
+#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
+#else
+#define CATCH_RECURSE(...)  CATCH_RECURSION_LEVEL5(__VA_ARGS__)
+#endif
+
+#define CATCH_REC_END(...)
+#define CATCH_REC_OUT
+
+#define CATCH_EMPTY()
+#define CATCH_DEFER(id) id CATCH_EMPTY()
+
+#define CATCH_REC_GET_END2() 0, CATCH_REC_END
+#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
+#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
+#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
+#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
+#define CATCH_REC_NEXT(test, next)  CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
+
+#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2(f, x, peek, ...)   f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
+
+#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...)   f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
+
+// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
+// and passes userdata as the first parameter to each invocation,
+// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
+#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
+
+#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param)
+#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__
+#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__
+#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
+#else
+// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
+#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
+#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
+#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
+#endif
+
+#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__)
+
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name, __VA_ARGS__)
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " - " #__VA_ARGS__
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name,...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
+#else
+// MSVC is adding extra space and needs more calls to properly remove ()
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME3(Name,...) Name " -" #__VA_ARGS__
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME2(Name, __VA_ARGS__)
+#define INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME(Name, ...) INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME1(Name, INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
+#endif
+
+#define INTERNAL_CATCH_MAKE_TYPE_LIST(types) Catch::TypeList<INTERNAL_CATCH_REMOVE_PARENS(types)>
+
+#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(types)\
+    CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,INTERNAL_CATCH_REMOVE_PARENS(types))
+
+#endif // TWOBLUECUBES_CATCH_PREPROCESSOR_HPP_INCLUDED
diff --git a/include/internal/catch_random_number_generator.cpp b/include/internal/catch_random_number_generator.cpp
index 412faeb..ec8a5eb 100644
--- a/include/internal/catch_random_number_generator.cpp
+++ b/include/internal/catch_random_number_generator.cpp
@@ -9,23 +9,21 @@
 #include "catch_context.h"
 #include "catch_interfaces_config.h"
 
-#include <cstdlib>
-
 namespace Catch {
 
-    void seedRng( IConfig const& config ) {
-        if( config.rngSeed() != 0 )
-            std::srand( config.rngSeed() );
+    std::mt19937& rng() {
+        static std::mt19937 s_rng;
+        return s_rng;
     }
+
+    void seedRng( IConfig const& config ) {
+        if( config.rngSeed() != 0 ) {
+            std::srand( config.rngSeed() );
+            rng().seed( config.rngSeed() );
+        }
+    }
+
     unsigned int rngSeed() {
         return getCurrentContext().getConfig()->rngSeed();
     }
-
-    RandomNumberGenerator::result_type RandomNumberGenerator::operator()( result_type n ) const {
-        return std::rand() % n;
-    }
-    RandomNumberGenerator::result_type RandomNumberGenerator::operator()() const {
-        return std::rand() % (max)();
-    }
-
 }
diff --git a/include/internal/catch_random_number_generator.h b/include/internal/catch_random_number_generator.h
index d18cffd..817b784 100644
--- a/include/internal/catch_random_number_generator.h
+++ b/include/internal/catch_random_number_generator.h
@@ -8,31 +8,16 @@
 #define TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
 
 #include <algorithm>
+#include <random>
 
 namespace Catch {
 
     struct IConfig;
 
+    std::mt19937& rng();
     void seedRng( IConfig const& config );
-
     unsigned int rngSeed();
 
-    struct RandomNumberGenerator {
-        using result_type = unsigned int;
-
-        static constexpr result_type (min)() { return 0; }
-        static constexpr result_type (max)() { return 1000000; }
-
-        result_type operator()( result_type n ) const;
-        result_type operator()() const;
-
-        template<typename V>
-        static void shuffle( V& vector ) {
-            RandomNumberGenerator rng;
-            std::shuffle( vector.begin(), vector.end(), rng );
-        }
-    };
-
 }
 
 #endif // TWOBLUECUBES_CATCH_RANDOM_NUMBER_GENERATOR_H_INCLUDED
diff --git a/include/internal/catch_registry_hub.cpp b/include/internal/catch_registry_hub.cpp
index d98708c..a506239 100644
--- a/include/internal/catch_registry_hub.cpp
+++ b/include/internal/catch_registry_hub.cpp
@@ -14,6 +14,7 @@
 #include "catch_exception_translator_registry.h"
 #include "catch_tag_alias_registry.h"
 #include "catch_startup_exception_registry.h"
+#include "catch_singletons.hpp"
 
 namespace Catch {
 
@@ -30,7 +31,7 @@
             ITestCaseRegistry const& getTestCaseRegistry() const override {
                 return m_testCaseRegistry;
             }
-            IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() override {
+            IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
                 return m_exceptionTranslatorRegistry;
             }
             ITagAliasRegistry const& getTagAliasRegistry() const override {
@@ -67,27 +68,19 @@
             TagAliasRegistry m_tagAliasRegistry;
             StartupExceptionRegistry m_exceptionRegistry;
         };
-
-        // Single, global, instance
-        RegistryHub*& getTheRegistryHub() {
-            static RegistryHub* theRegistryHub = nullptr;
-            if( !theRegistryHub )
-                theRegistryHub = new RegistryHub();
-            return theRegistryHub;
-        }
     }
 
-    IRegistryHub& getRegistryHub() {
-        return *getTheRegistryHub();
+    using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
+
+    IRegistryHub const& getRegistryHub() {
+        return RegistryHubSingleton::get();
     }
     IMutableRegistryHub& getMutableRegistryHub() {
-        return *getTheRegistryHub();
+        return RegistryHubSingleton::getMutable();
     }
     void cleanUp() {
-        delete getTheRegistryHub();
-        getTheRegistryHub() = nullptr;
+        cleanupSingletons();
         cleanUpContext();
-        ReusableStringStream::cleanup();
     }
     std::string translateActiveException() {
         return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
diff --git a/include/internal/catch_run_context.cpp b/include/internal/catch_run_context.cpp
index 83de539..bc3a515 100644
--- a/include/internal/catch_run_context.cpp
+++ b/include/internal/catch_run_context.cpp
@@ -1,8 +1,10 @@
 #include "catch_run_context.h"
+#include "catch_compiler_capabilities.h"
 #include "catch_context.h"
 #include "catch_enforce.h"
 #include "catch_random_number_generator.h"
 #include "catch_stream.h"
+#include "catch_output_redirect.h"
 
 #include <cassert>
 #include <algorithm>
@@ -10,55 +12,68 @@
 
 namespace Catch {
 
-    class RedirectedStream {
-        std::ostream& m_originalStream;
-        std::ostream& m_redirectionStream;
-        std::streambuf* m_prevBuf;
+    namespace Generators {
+        struct GeneratorTracker : TestCaseTracking::TrackerBase, IGeneratorTracker {
+            GeneratorBasePtr m_generator;
 
-    public:
-        RedirectedStream( std::ostream& originalStream, std::ostream& redirectionStream )
-        :   m_originalStream( originalStream ),
-            m_redirectionStream( redirectionStream ),
-            m_prevBuf( m_originalStream.rdbuf() )
-        {
-            m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
-        }
-        ~RedirectedStream() {
-            m_originalStream.rdbuf( m_prevBuf );
-        }
-    };
+            GeneratorTracker( TestCaseTracking::NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
+            :   TrackerBase( nameAndLocation, ctx, parent )
+            {}
+            ~GeneratorTracker();
 
-    class RedirectedStdOut {
-        ReusableStringStream m_rss;
-        RedirectedStream m_cout;
-    public:
-        RedirectedStdOut() : m_cout( Catch::cout(), m_rss.get() ) {}
-        auto str() const -> std::string { return m_rss.str(); }
-    };
+            static GeneratorTracker& acquire( TrackerContext& ctx, TestCaseTracking::NameAndLocation const& nameAndLocation ) {
+                std::shared_ptr<GeneratorTracker> tracker;
 
-    // StdErr has two constituent streams in C++, std::cerr and std::clog
-    // This means that we need to redirect 2 streams into 1 to keep proper
-    // order of writes
-    class RedirectedStdErr {
-        ReusableStringStream m_rss;
-        RedirectedStream m_cerr;
-        RedirectedStream m_clog;
-    public:
-        RedirectedStdErr()
-        :   m_cerr( Catch::cerr(), m_rss.get() ),
-            m_clog( Catch::clog(), m_rss.get() )
-        {}
-        auto str() const -> std::string { return m_rss.str(); }
-    };
+                ITracker& currentTracker = ctx.currentTracker();
+                if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
+                    assert( childTracker );
+                    assert( childTracker->isGeneratorTracker() );
+                    tracker = std::static_pointer_cast<GeneratorTracker>( childTracker );
+                }
+                else {
+                    tracker = std::make_shared<GeneratorTracker>( nameAndLocation, ctx, &currentTracker );
+                    currentTracker.addChild( tracker );
+                }
 
+                if( !ctx.completedCycle() && !tracker->isComplete() ) {
+                    tracker->open();
+                }
+
+                return *tracker;
+            }
+
+            // TrackerBase interface
+            bool isGeneratorTracker() const override { return true; }
+            auto hasGenerator() const -> bool override {
+                return !!m_generator;
+            }
+            void close() override {
+                TrackerBase::close();
+                // Generator interface only finds out if it has another item on atual move
+                if (m_runState == CompletedSuccessfully && m_generator->next()) {
+                    m_children.clear();
+                    m_runState = Executing;
+                }
+            }
+
+            // IGeneratorTracker interface
+            auto getGenerator() const -> GeneratorBasePtr const& override {
+                return m_generator;
+            }
+            void setGenerator( GeneratorBasePtr&& generator ) override {
+                m_generator = std::move( generator );
+            }
+        };
+        GeneratorTracker::~GeneratorTracker() {}
+    }
 
     RunContext::RunContext(IConfigPtr const& _config, IStreamingReporterPtr&& reporter)
     :   m_runInfo(_config->name()),
         m_context(getCurrentMutableContext()),
         m_config(_config),
         m_reporter(std::move(reporter)),
-        m_lastAssertionInfo{ "", SourceLineInfo("",0), "", ResultDisposition::Normal },
-        m_includeSuccessfulResults( m_config->includeSuccessfulResults() )
+        m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
+        m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
     {
         m_context.setRunner(this);
         m_context.setConfig(m_config);
@@ -84,7 +99,7 @@
         std::string redirectedCout;
         std::string redirectedCerr;
 
-        TestCaseInfo testInfo = testCase.getTestCaseInfo();
+        auto const& testInfo = testCase.getTestCaseInfo();
 
         m_reporter->testCaseStarting(testInfo);
 
@@ -146,6 +161,9 @@
         // and should be let to clear themselves out.
         static_cast<void>(m_reporter->assertionEnded(AssertionStats(result, m_messages, m_totals)));
 
+        if (result.getResultType() != ResultWas::Warning)
+            m_messageScopes.clear();
+
         // Reset working state
         resetAssertionInfo();
         m_lastResult = result;
@@ -169,6 +187,13 @@
 
         return true;
     }
+    auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& {
+        using namespace Generators;
+        GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) );
+        assert( tracker.isOpen() );
+        m_lastAssertionInfo.lineInfo = lineInfo;
+        return tracker;
+    }
 
     bool RunContext::testForMissingAssertions(Counts& assertions) {
         if (assertions.total() != 0)
@@ -193,6 +218,7 @@
 
         m_reporter->sectionEnded(SectionStats(endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions));
         m_messages.clear();
+        m_messageScopes.clear();
     }
 
     void RunContext::sectionEndedEarly(SectionEndInfo const & endInfo) {
@@ -219,6 +245,10 @@
         m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
     }
 
+    void RunContext::emplaceUnscopedMessage( MessageBuilder const& builder ) {
+        m_messageScopes.emplace_back( builder );
+    }
+
     std::string RunContext::getCurrentTestName() const {
         return m_activeTestCase
             ? m_activeTestCase->getTestCaseInfo().name
@@ -249,7 +279,7 @@
 
         // Recreate section for test case (as we will lose the one that was in scope)
         auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
-        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
 
         Counts assertions;
         assertions.failed = 1;
@@ -279,41 +309,45 @@
         m_lastAssertionPassed = true;
         ++m_totals.assertions.passed;
         resetAssertionInfo();
+        m_messageScopes.clear();
     }
 
     bool RunContext::aborting() const {
-        return m_totals.assertions.failed == static_cast<std::size_t>(m_config->abortAfter());
+        return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
     }
 
     void RunContext::runCurrentTest(std::string & redirectedCout, std::string & redirectedCerr) {
         auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
-        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description);
+        SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
         m_reporter->sectionStarting(testCaseSection);
         Counts prevAssertions = m_totals.assertions;
         double duration = 0;
         m_shouldReportUnexpected = true;
-        m_lastAssertionInfo = { "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal };
+        m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
 
         seedRng(*m_config);
 
         Timer timer;
-        CATCH_INTERNAL_TRY {
+        CATCH_TRY {
             if (m_reporter->getPreferences().shouldRedirectStdOut) {
-                RedirectedStdOut redirectedStdOut;
-                RedirectedStdErr redirectedStdErr;
+#if !defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
+                RedirectedStreams redirectedStreams(redirectedCout, redirectedCerr);
+
                 timer.start();
                 invokeActiveTestCase();
-                redirectedCout += redirectedStdOut.str();
-                redirectedCerr += redirectedStdErr.str();
-
+#else
+                OutputRedirect r(redirectedCout, redirectedCerr);
+                timer.start();
+                invokeActiveTestCase();
+#endif
             } else {
                 timer.start();
                 invokeActiveTestCase();
             }
             duration = timer.getElapsedSeconds();
-        } CATCH_INTERNAL_CATCH_UNNAMED (TestFailureException&) {
+        } CATCH_CATCH_ANON (TestFailureException&) {
             // This just means the test was aborted due to failure
-        } CATCH_INTERNAL_CATCH_ALL() {
+        } CATCH_CATCH_ALL {
             // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
             // are reported without translation at the point of origin.
             if( m_shouldReportUnexpected ) {
@@ -327,6 +361,7 @@
         m_testCaseTracker->close();
         handleUnfinishedSections();
         m_messages.clear();
+        m_messageScopes.clear();
 
         SectionStats testCaseSectionStats(testCaseSection, assertions, duration, missingAssertions);
         m_reporter->sectionEnded(testCaseSectionStats);
diff --git a/include/internal/catch_run_context.h b/include/internal/catch_run_context.h
index d0007a3..c530a7b 100644
--- a/include/internal/catch_run_context.h
+++ b/include/internal/catch_run_context.h
@@ -8,6 +8,7 @@
 #ifndef TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
 
+#include "catch_interfaces_generatortracker.h"
 #include "catch_interfaces_runner.h"
 #include "catch_interfaces_reporter.h"
 #include "catch_interfaces_exception.h"
@@ -79,12 +80,16 @@
         void sectionEnded( SectionEndInfo const& endInfo ) override;
         void sectionEndedEarly( SectionEndInfo const& endInfo ) override;
 
+        auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override;
+
         void benchmarkStarting( BenchmarkInfo const& info ) override;
         void benchmarkEnded( BenchmarkStats const& stats ) override;
 
         void pushScopedMessage( MessageInfo const& message ) override;
         void popScopedMessage( MessageInfo const& message ) override;
 
+        void emplaceUnscopedMessage( MessageBuilder const& builder ) override;
+
         std::string getCurrentTestName() const override;
 
         const AssertionResult* getLastResult() const override;
@@ -99,7 +104,7 @@
 
     public:
         // !TBD We need to do this another way!
-        bool aborting() const override;
+        bool aborting() const final;
 
     private:
 
@@ -125,13 +130,14 @@
         TestRunInfo m_runInfo;
         IMutableContext& m_context;
         TestCase const* m_activeTestCase = nullptr;
-        ITracker* m_testCaseTracker;
+        ITracker* m_testCaseTracker = nullptr;
         Option<AssertionResult> m_lastResult;
 
         IConfigPtr m_config;
         Totals m_totals;
         IStreamingReporterPtr m_reporter;
         std::vector<MessageInfo> m_messages;
+        std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
         AssertionInfo m_lastAssertionInfo;
         std::vector<SectionEndInfo> m_unfinishedSections;
         std::vector<ITracker*> m_activeSections;
diff --git a/include/internal/catch_section.cpp b/include/internal/catch_section.cpp
index 72a57d5..0646d36 100644
--- a/include/internal/catch_section.cpp
+++ b/include/internal/catch_section.cpp
@@ -21,7 +21,7 @@
 
     Section::~Section() {
         if( m_sectionIncluded ) {
-            SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() );
+            SectionEndInfo endInfo{ m_info, m_assertions, m_timer.getElapsedSeconds() };
             if( uncaught_exceptions() )
                 getResultCapture().sectionEndedEarly( endInfo );
             else
diff --git a/include/internal/catch_section.h b/include/internal/catch_section.h
index 1e5b1c3..00c254b 100644
--- a/include/internal/catch_section.h
+++ b/include/internal/catch_section.h
@@ -8,6 +8,7 @@
 #ifndef TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
 #define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
 
+#include "catch_compiler_capabilities.h"
 #include "catch_section_info.h"
 #include "catch_totals.h"
 #include "catch_timer.h"
@@ -35,7 +36,14 @@
 
 } // end namespace Catch
 
-    #define INTERNAL_CATCH_SECTION( ... ) \
-        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#define INTERNAL_CATCH_SECTION( ... ) \
+    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
+    CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
+
+#define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
+    CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \
+    if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, (Catch::ReusableStringStream() << __VA_ARGS__).str() ) ) \
+    CATCH_INTERNAL_UNSUPPRESS_UNUSED_WARNINGS
 
 #endif // TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
diff --git a/include/internal/catch_section_info.cpp b/include/internal/catch_section_info.cpp
index e2846b8..89714e3 100644
--- a/include/internal/catch_section_info.cpp
+++ b/include/internal/catch_section_info.cpp
@@ -11,15 +11,9 @@
 
     SectionInfo::SectionInfo
         (   SourceLineInfo const& _lineInfo,
-            std::string const& _name,
-            std::string const& _description )
+            std::string const& _name )
     :   name( _name ),
-        description( _description ),
         lineInfo( _lineInfo )
     {}
 
-    SectionEndInfo::SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds )
-    : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
-    {}
-
 } // end namespace Catch
diff --git a/include/internal/catch_section_info.h b/include/internal/catch_section_info.h
index 86681ba..9cf792e 100644
--- a/include/internal/catch_section_info.h
+++ b/include/internal/catch_section_info.h
@@ -18,17 +18,20 @@
     struct SectionInfo {
         SectionInfo
             (   SourceLineInfo const& _lineInfo,
+                std::string const& _name );
+
+        // Deprecated
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
                 std::string const& _name,
-                std::string const& _description = std::string() );
+                std::string const& ) : SectionInfo( _lineInfo, _name ) {}
 
         std::string name;
-        std::string description;
+        std::string description; // !Deprecated: this will always be empty
         SourceLineInfo lineInfo;
     };
 
     struct SectionEndInfo {
-        SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds );
-
         SectionInfo sectionInfo;
         Counts prevAssertions;
         double durationInSeconds;
diff --git a/include/internal/catch_session.cpp b/include/internal/catch_session.cpp
index 34ac571..a5907e9 100644
--- a/include/internal/catch_session.cpp
+++ b/include/internal/catch_session.cpp
@@ -5,12 +5,12 @@
  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  */
 
-#include "catch_common.h"
 #include "catch_session.h"
 #include "catch_commandline.h"
 #include "catch_console_colour.h"
 #include "catch_enforce.h"
 #include "catch_list.h"
+#include "catch_context.h"
 #include "catch_run_context.h"
 #include "catch_stream.h"
 #include "catch_test_spec.h"
@@ -19,6 +19,9 @@
 #include "catch_random_number_generator.h"
 #include "catch_startup_exception_registry.h"
 #include "catch_text.h"
+#include "catch_stream.h"
+#include "catch_windows_h_proxy.h"
+#include "../reporters/catch_reporter_listening.h"
 
 #include <cstdlib>
 #include <iomanip>
@@ -35,33 +38,29 @@
             return reporter;
         }
 
-#ifndef CATCH_CONFIG_DEFAULT_REPORTER
-#define CATCH_CONFIG_DEFAULT_REPORTER "console"
-#endif
-
         IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
-            auto const& reporterNames = config->getReporterNames();
-            if (reporterNames.empty())
-                return createReporter(CATCH_CONFIG_DEFAULT_REPORTER, config);
+            if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
+                return createReporter(config->getReporterName(), config);
+            }
 
-            IStreamingReporterPtr reporter;
-            for (auto const& name : reporterNames)
-                addReporter(reporter, createReporter(name, config));
-            return reporter;
-        }
-
-#undef CATCH_CONFIG_DEFAULT_REPORTER
-
-        void addListeners(IStreamingReporterPtr& reporters, IConfigPtr const& config) {
+            // On older platforms, returning std::unique_ptr<ListeningReporter>
+            // when the return type is std::unique_ptr<IStreamingReporter>
+            // doesn't compile without a std::move call. However, this causes
+            // a warning on newer platforms. Thus, we have to work around
+            // it a bit and downcast the pointer manually.
+            auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
+            auto& multi = static_cast<ListeningReporter&>(*ret);
             auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
-            for (auto const& listener : listeners)
-                addReporter(reporters, listener->create(Catch::ReporterConfig(config)));
+            for (auto const& listener : listeners) {
+                multi.addListener(listener->create(Catch::ReporterConfig(config)));
+            }
+            multi.addReporter(createReporter(config->getReporterName(), config));
+            return ret;
         }
 
 
         Catch::Totals runTests(std::shared_ptr<Config> const& config) {
-            IStreamingReporterPtr reporter = makeReporter(config);
-            addListeners(reporter, config);
+            auto reporter = makeReporter(config);
 
             RunContext context(config, std::move(reporter));
 
@@ -70,8 +69,6 @@
             context.testGroupStarting(config->name(), 1, 1);
 
             TestSpec testSpec = config->testSpec();
-            if (!testSpec.hasFilters())
-                testSpec = TestSpecParser(ITagAliasRegistry::get()).parse("~[.]").testSpec(); // All not hidden tests
 
             auto const& allTestCases = getAllTestCasesSorted(*config);
             for (auto const& testCase : allTestCases) {
@@ -81,6 +78,20 @@
                     context.reporter().skipTest(testCase);
             }
 
+            if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
+                ReusableStringStream testConfig;
+
+                bool first = true;
+                for (const auto& input : config->getTestsOrTags()) {
+                    if (!first) { testConfig << ' '; }
+                    first = false;
+                    testConfig << input;
+                }
+
+                context.reporter().noMatchingTestCases(testConfig.str());
+                totals.error = -1;
+            }
+
             context.testGroupEnded(config->name(), totals, 1, 1);
             return totals;
         }
@@ -112,26 +123,27 @@
     Session::Session() {
         static bool alreadyInstantiated = false;
         if( alreadyInstantiated ) {
-            CATCH_INTERNAL_TRY {
-                CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" );
-            }
-            CATCH_INTERNAL_CATCH_ALL() { getMutableRegistryHub().registerStartupException(); }
+            CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
+            CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
         }
 
+        // There cannot be exceptions at startup in no-exception mode.
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
         const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
         if ( !exceptions.empty() ) {
             m_startupExceptions = true;
             Colour colourGuard( Colour::Red );
-            Catch::cerr() << "Errors occured during startup!" << '\n';
+            Catch::cerr() << "Errors occurred during startup!" << '\n';
             // iterate over all exceptions and notify user
             for ( const auto& ex_ptr : exceptions ) {
-                CATCH_INTERNAL_TRY {
+                try {
                     std::rethrow_exception(ex_ptr);
-                } CATCH_INTERNAL_CATCH ( std::exception const&, ex ) {
+                } catch ( std::exception const& ex ) {
                     Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
                 }
             }
         }
+#endif
 
         alreadyInstantiated = true;
         m_cli = makeCommandLineParser( m_configData );
@@ -154,12 +166,14 @@
                 << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
     }
 
-    int Session::applyCommandLine( int argc, char* argv[] ) {
+    int Session::applyCommandLine( int argc, char const * const * argv ) {
         if( m_startupExceptions )
             return 1;
 
         auto result = m_cli.parse( clara::Args( argc, argv ) );
         if( !result ) {
+            config();
+            getCurrentMutableContext().setConfig(m_config);
             Catch::cerr()
                 << Colour( Colour::Red )
                 << "\nError(s) in input:\n"
@@ -177,22 +191,8 @@
         return 0;
     }
 
-    void Session::useConfigData( ConfigData const& configData ) {
-        m_configData = configData;
-        m_config.reset();
-    }
-
-    int Session::run( int argc, char* argv[] ) {
-        if( m_startupExceptions )
-            return 1;
-        int returnCode = applyCommandLine( argc, argv );
-        if( returnCode == 0 )
-            returnCode = run();
-        return returnCode;
-    }
-
-#if defined(WIN32) && defined(UNICODE)
-    int Session::run( int argc, wchar_t* const argv[] ) {
+#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+    int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
 
         char **utf8Argv = new char *[ argc ];
 
@@ -204,7 +204,7 @@
             WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
         }
 
-        int returnCode = run( argc, utf8Argv );
+        int returnCode = applyCommandLine( argc, utf8Argv );
 
         for ( int i = 0; i < argc; ++i )
             delete [] utf8Argv[ i ];
@@ -214,6 +214,12 @@
         return returnCode;
     }
 #endif
+
+    void Session::useConfigData( ConfigData const& configData ) {
+        m_configData = configData;
+        m_config.reset();
+    }
+
     int Session::run() {
         if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
             Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
@@ -246,11 +252,11 @@
         if( m_startupExceptions )
             return 1;
 
-        if( m_configData.showHelp || m_configData.libIdentify )
+        if (m_configData.showHelp || m_configData.libIdentify) {
             return 0;
+        }
 
-        CATCH_INTERNAL_TRY
-        {
+        CATCH_TRY {
             config(); // Force config to be constructed
 
             seedRng( *m_config );
@@ -259,18 +265,21 @@
                 applyFilenamesAsTags( *m_config );
 
             // Handle list request
-            if( Option<std::size_t> listed = list( config() ) )
+            if( Option<std::size_t> listed = list( m_config ) )
                 return static_cast<int>( *listed );
 
+            auto totals = runTests( m_config );
             // Note that on unices only the lower 8 bits are usually used, clamping
             // the return value to 255 prevents false negative when some multiple
             // of 256 tests has failed
-            return (std::min)( MaxExitCode, static_cast<int>( runTests( m_config ).assertions.failed ) );
+            return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
         }
-        CATCH_INTERNAL_CATCH ( std::exception&, ex ) {
+#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
+        catch( std::exception& ex ) {
             Catch::cerr() << ex.what() << std::endl;
             return MaxExitCode;
         }
+#endif
     }
 
 } // end namespace Catch
diff --git a/include/internal/catch_session.h b/include/internal/catch_session.h
index b814aa6..af820da 100644
--- a/include/internal/catch_session.h
+++ b/include/internal/catch_session.h
@@ -25,14 +25,23 @@
         void showHelp() const;
         void libIdentify();
 
-        int applyCommandLine( int argc, char* argv[] );
+        int applyCommandLine( int argc, char const * const * argv );
+    #if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
+        int applyCommandLine( int argc, wchar_t const * const * argv );
+    #endif
 
         void useConfigData( ConfigData const& configData );
 
-        int run( int argc, char* argv[] );
-    #if defined(WIN32) && defined(UNICODE)
-        int run( int argc, wchar_t* const argv[] );
-    #endif
+        template<typename CharT>
+        int run(int argc, CharT const * const argv[]) {
+            if (m_startupExceptions)
+                return 1;
+            int returnCode = applyCommandLine(argc, argv);
+            if (returnCode == 0)
+                returnCode = run();
+            return returnCode;
+        }
+    
         int run();
 
         clara::Parser const& cli() const;
diff --git a/include/internal/catch_singletons.cpp b/include/internal/catch_singletons.cpp
new file mode 100644
index 0000000..e5367ca
--- /dev/null
+++ b/include/internal/catch_singletons.cpp
@@ -0,0 +1,36 @@
+/*
+ *  Created by Phil Nash on 15/6/2018.
+ *
+ *  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 "catch_singletons.hpp"
+
+#include <vector>
+
+namespace Catch {
+
+    namespace {
+        static auto getSingletons() -> std::vector<ISingleton*>*& {
+            static std::vector<ISingleton*>* g_singletons = nullptr;
+            if( !g_singletons )
+                g_singletons = new std::vector<ISingleton*>();
+            return g_singletons;
+        }
+    }
+
+    ISingleton::~ISingleton() {}
+
+    void addSingleton(ISingleton* singleton ) {
+        getSingletons()->push_back( singleton );
+    }
+    void cleanupSingletons() {
+        auto& singletons = getSingletons();
+        for( auto singleton : *singletons )
+            delete singleton;
+        delete singletons;
+        singletons = nullptr;
+    }
+
+} // namespace Catch
diff --git a/include/internal/catch_singletons.hpp b/include/internal/catch_singletons.hpp
new file mode 100644
index 0000000..fbc4b32
--- /dev/null
+++ b/include/internal/catch_singletons.hpp
@@ -0,0 +1,44 @@
+/*
+ *  Created by Phil Nash on 15/6/2018.
+ *
+ *  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_CATCH_SINGLETONS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
+
+namespace Catch {
+
+    struct ISingleton {
+        virtual ~ISingleton();
+    };
+
+
+    void addSingleton( ISingleton* singleton );
+    void cleanupSingletons();
+
+
+    template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
+    class Singleton : SingletonImplT, public ISingleton {
+
+        static auto getInternal() -> Singleton* {
+            static Singleton* s_instance = nullptr;
+            if( !s_instance ) {
+                s_instance = new Singleton;
+                addSingleton( s_instance );
+            }
+            return s_instance;
+        }
+
+    public:
+        static auto get() -> InterfaceT const& {
+            return *getInternal();
+        }
+        static auto getMutable() -> MutableInterfaceT& {
+            return *getInternal();
+        }
+    };
+
+} // namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_SINGLETONS_HPP_INCLUDED
diff --git a/include/internal/catch_startup_exception_registry.cpp b/include/internal/catch_startup_exception_registry.cpp
index 7eae84f..3c5bd22 100644
--- a/include/internal/catch_startup_exception_registry.cpp
+++ b/include/internal/catch_startup_exception_registry.cpp
@@ -7,14 +7,13 @@
  */
 
 #include "catch_startup_exception_registry.h"
-#include "catch_common.h"
+#include "catch_compiler_capabilities.h"
 
 namespace Catch {
-    void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
-        CATCH_INTERNAL_TRY {
+void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
+        CATCH_TRY {
             m_exceptions.push_back(exception);
-        }
-        CATCH_INTERNAL_CATCH_ALL() {
+        } CATCH_CATCH_ALL {
             // If we run out of memory during start-up there's really not a lot more we can do about it
             std::terminate();
         }
diff --git a/include/internal/catch_stream.cpp b/include/internal/catch_stream.cpp
index 125fd47..ba2d2be 100644
--- a/include/internal/catch_stream.cpp
+++ b/include/internal/catch_stream.cpp
@@ -12,6 +12,7 @@
 #include "catch_stream.h"
 #include "catch_debug_console.h"
 #include "catch_stringref.h"
+#include "catch_singletons.hpp"
 
 #include <cstdio>
 #include <iostream>
@@ -20,11 +21,6 @@
 #include <vector>
 #include <memory>
 
-#if defined(__clang__)
-#    pragma clang diagnostic push
-#    pragma clang diagnostic ignored "-Wexit-time-destructors"
-#endif
-
 namespace Catch {
 
     Catch::IStream::~IStream() = default;
@@ -145,7 +141,6 @@
         std::vector<std::unique_ptr<std::ostringstream>> m_streams;
         std::vector<std::size_t> m_unused;
         std::ostringstream m_referenceStream; // Used for copy state/ flags from
-        static StringStreams* s_instance;
 
         auto add() -> std::size_t {
             if( m_unused.empty() ) {
@@ -163,34 +158,17 @@
             m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
             m_unused.push_back(index);
         }
-
-        // !TBD: put in TLS
-        static auto instance() -> StringStreams& {
-            if( !s_instance )
-                s_instance = new StringStreams();
-            return *s_instance;
-        }
-        static void cleanup() {
-            delete s_instance;
-            s_instance = nullptr;
-        }
     };
 
-    StringStreams* StringStreams::s_instance = nullptr;
-
-    void ReusableStringStream::cleanup() {
-        StringStreams::cleanup();
-    }
-
     ReusableStringStream::ReusableStringStream()
-    :   m_index( StringStreams::instance().add() ),
-        m_oss( StringStreams::instance().m_streams[m_index].get() )
+    :   m_index( Singleton<StringStreams>::getMutable().add() ),
+        m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
     {}
 
     ReusableStringStream::~ReusableStringStream() {
         static_cast<std::ostringstream*>( m_oss )->str("");
         m_oss->clear();
-        StringStreams::instance().release( m_index );
+        Singleton<StringStreams>::getMutable().release( m_index );
     }
 
     auto ReusableStringStream::str() const -> std::string {
@@ -207,7 +185,3 @@
     std::ostream& clog() { return std::clog; }
 #endif
 }
-
-#if defined(__clang__)
-#    pragma clang diagnostic pop
-#endif
diff --git a/include/internal/catch_stream.h b/include/internal/catch_stream.h
index c5e78b2..2b41adb 100644
--- a/include/internal/catch_stream.h
+++ b/include/internal/catch_stream.h
@@ -43,8 +43,6 @@
             return *this;
         }
         auto get() -> std::ostream& { return *m_oss; }
-
-        static void cleanup();
     };
 }
 
diff --git a/include/internal/catch_string_manip.cpp b/include/internal/catch_string_manip.cpp
index 8476204..904d101 100644
--- a/include/internal/catch_string_manip.cpp
+++ b/include/internal/catch_string_manip.cpp
@@ -14,6 +14,12 @@
 
 namespace Catch {
 
+    namespace {
+        char toLowerCh(char c) {
+            return static_cast<char>( std::tolower( c ) );
+        }
+    }
+
     bool startsWith( std::string const& s, std::string const& prefix ) {
         return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
     }
@@ -29,9 +35,6 @@
     bool contains( std::string const& s, std::string const& infix ) {
         return s.find( infix ) != std::string::npos;
     }
-    char toLowerCh(char c) {
-        return static_cast<char>( std::tolower( c ) );
-    }
     void toLowerInPlace( std::string& s ) {
         std::transform( s.begin(), s.end(), s.begin(), toLowerCh );
     }
diff --git a/include/internal/catch_stringref.cpp b/include/internal/catch_stringref.cpp
index b0b2f8e..9e9095e 100644
--- a/include/internal/catch_stringref.cpp
+++ b/include/internal/catch_stringref.cpp
@@ -43,7 +43,7 @@
            const_cast<StringRef*>( this )->takeOwnership();
         return m_start;
     }
-    auto StringRef::data() const noexcept -> char const* {
+    auto StringRef::currentData() const noexcept -> char const* {
         return m_start;
     }
 
@@ -112,7 +112,12 @@
     }
 
     auto operator << ( std::ostream& os, StringRef const& str ) -> std::ostream& {
-        return os << str.c_str();
+        return os.write(str.currentData(), str.size());
+    }
+
+    auto operator+=( std::string& lhs, StringRef const& rhs ) -> std::string& {
+        lhs.append(rhs.currentData(), rhs.size());
+        return lhs;
     }
 
 } // namespace Catch
diff --git a/include/internal/catch_stringref.h b/include/internal/catch_stringref.h
index 0f9e780..64f595b 100644
--- a/include/internal/catch_stringref.h
+++ b/include/internal/catch_stringref.h
@@ -12,8 +12,6 @@
 #include <iosfwd>
 
 namespace Catch {
-    
-    class StringData;
 
     /// A non-owning string class (similar to the forthcoming std::string_view)
     /// Note that, because a StringRef may be a substring of another string,
@@ -31,13 +29,13 @@
 
         char const* m_start;
         size_type m_size;
-        
+
         char* m_data = nullptr;
-        
+
         void takeOwnership();
 
         static constexpr char const* const s_empty = "";
-        
+
     public: // construction/ assignment
         StringRef() noexcept
         :   StringRef( s_empty, 0 )
@@ -83,13 +81,13 @@
         operator std::string() const;
 
         void swap( StringRef& other ) noexcept;
-        
+
     public: // operators
         auto operator == ( StringRef const& other ) const noexcept -> bool;
         auto operator != ( StringRef const& other ) const noexcept -> bool;
-        
+
         auto operator[] ( size_type index ) const noexcept -> char;
-        
+
     public: // named queries
         auto empty() const noexcept -> bool {
             return m_size == 0;
@@ -100,26 +98,35 @@
 
         auto numberOfCharacters() const noexcept -> size_type;
         auto c_str() const -> char const*;
-        
+
     public: // substrings and searches
         auto substr( size_type start, size_type size ) const noexcept -> StringRef;
 
+        // Returns the current start pointer.
+        // Note that the pointer can change when if the StringRef is a substring
+        auto currentData() const noexcept -> char const*;
+
     private: // ownership queries - may not be consistent between calls
         auto isOwned() const noexcept -> bool;
         auto isSubstring() const noexcept -> bool;
-        auto data() const noexcept -> char const*;
     };
 
     auto operator + ( StringRef const& lhs, StringRef const& rhs ) -> std::string;
     auto operator + ( StringRef const& lhs, char const* rhs ) -> std::string;
     auto operator + ( char const* lhs, StringRef const& rhs ) -> std::string;
 
+    auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&;
     auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&;
 
+
     inline auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
         return StringRef( rawChars, size );
     }
 
 } // namespace Catch
 
+inline auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
+    return Catch::StringRef( rawChars, size );
+}
+
 #endif // CATCH_STRINGREF_H_INCLUDED
diff --git a/include/internal/catch_suppress_warnings.h b/include/internal/catch_suppress_warnings.h
index 9280114..dc8c1da 100644
--- a/include/internal/catch_suppress_warnings.h
+++ b/include/internal/catch_suppress_warnings.h
@@ -10,15 +10,18 @@
 #       pragma warning(push)
 #       pragma warning(disable: 161 1682)
 #   else // __ICC
-#       pragma clang diagnostic ignored "-Wunused-variable"
 #       pragma clang diagnostic push
 #       pragma clang diagnostic ignored "-Wpadded"
 #       pragma clang diagnostic ignored "-Wswitch-enum"
 #       pragma clang diagnostic ignored "-Wcovered-switch-default"
 #    endif
 #elif defined __GNUC__
-#    pragma GCC diagnostic ignored "-Wunused-variable"
-#    pragma GCC diagnostic ignored "-Wparentheses"
+     // Because REQUIREs trigger GCC's -Wparentheses, and because still
+     // supported version of g++ have only buggy support for _Pragmas,
+     // Wparentheses have to be suppressed globally.
+#    pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details
+
 #    pragma GCC diagnostic push
+#    pragma GCC diagnostic ignored "-Wunused-variable"
 #    pragma GCC diagnostic ignored "-Wpadded"
 #endif
diff --git a/include/internal/catch_tag_alias_autoregistrar.cpp b/include/internal/catch_tag_alias_autoregistrar.cpp
index b5c6ce9..6a292ed 100644
--- a/include/internal/catch_tag_alias_autoregistrar.cpp
+++ b/include/internal/catch_tag_alias_autoregistrar.cpp
@@ -1,12 +1,13 @@
 #include "catch_tag_alias_autoregistrar.h"
+#include "catch_compiler_capabilities.h"
 #include "catch_interfaces_registry_hub.h"
 
 namespace Catch {
-    
+
     RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
-        CATCH_INTERNAL_TRY {
+        CATCH_TRY {
             getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
-        } CATCH_INTERNAL_CATCH_ALL() {
+        } CATCH_CATCH_ALL {
             // Do not throw when constructing global objects, instead register the exception to be processed later
             getMutableRegistryHub().registerStartupException();
         }
diff --git a/include/internal/catch_test_case_info.cpp b/include/internal/catch_test_case_info.cpp
index 4ab9775..536462d 100644
--- a/include/internal/catch_test_case_info.cpp
+++ b/include/internal/catch_test_case_info.cpp
@@ -19,37 +19,38 @@
 
 namespace Catch {
 
-    TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
-        if( startsWith( tag, '.' ) ||
-            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 if( tag == "!nonportable" )
-            return TestCaseInfo::NonPortable;
-        else if( tag == "!benchmark" )
-            return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
-        else
-            return TestCaseInfo::None;
-    }
-    bool isReservedTag( std::string const& tag ) {
-        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( tag[0] );
-    }
-    void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
-        CATCH_ENFORCE( !isReservedTag(tag),
-                      "Tag name: [" << tag << "] is not allowed.\n"
-                      << "Tag names starting with non alpha-numeric characters are reserved\n"
-                      << _lineInfo );
+    namespace {
+        TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+            if( startsWith( tag, '.' ) ||
+                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 if( tag == "!nonportable" )
+                return TestCaseInfo::NonPortable;
+            else if( tag == "!benchmark" )
+                return static_cast<TestCaseInfo::SpecialProperties>( TestCaseInfo::Benchmark | TestCaseInfo::IsHidden );
+            else
+                return TestCaseInfo::None;
+        }
+        bool isReservedTag( std::string const& tag ) {
+            return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
+        }
+        void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+            CATCH_ENFORCE( !isReservedTag(tag),
+                          "Tag name: [" << tag << "] is not allowed.\n"
+                          << "Tag names starting with non alpha-numeric characters are reserved\n"
+                          << _lineInfo );
+        }
     }
 
     TestCase makeTestCase(  ITestInvoker* _testCase,
                             std::string const& _className,
-                            std::string const& _name,
-                            std::string const& _descOrTags,
+                            NameAndTags const& nameAndTags,
                             SourceLineInfo const& _lineInfo )
     {
         bool isHidden = false;
@@ -58,6 +59,7 @@
         std::vector<std::string> tags;
         std::string desc, tag;
         bool inTag = false;
+        std::string _descOrTags = nameAndTags.tags;
         for (char c : _descOrTags) {
             if( !inTag ) {
                 if( c == '[' )
@@ -85,8 +87,8 @@
             tags.push_back( "." );
         }
 
-        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
-        return TestCase( _testCase, info );
+        TestCaseInfo info( nameAndTags.name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, std::move(info) );
     }
 
     void setTags( TestCaseInfo& testCaseInfo, std::vector<std::string> tags ) {
@@ -147,7 +149,7 @@
     }
 
 
-    TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+    TestCase::TestCase( ITestInvoker* testCase, TestCaseInfo&& info ) : TestCaseInfo( std::move(info) ), test( testCase ) {}
 
 
     TestCase TestCase::withName( std::string const& _newName ) const {
diff --git a/include/internal/catch_test_case_info.h b/include/internal/catch_test_case_info.h
index 2a911b0..809c974 100644
--- a/include/internal/catch_test_case_info.h
+++ b/include/internal/catch_test_case_info.h
@@ -9,6 +9,7 @@
 #define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
 
 #include "catch_common.h"
+#include "catch_test_registry.h"
 
 #include <string>
 #include <vector>
@@ -61,7 +62,7 @@
     class TestCase : public TestCaseInfo {
     public:
 
-        TestCase( ITestInvoker* testCase, TestCaseInfo const& info );
+        TestCase( ITestInvoker* testCase, TestCaseInfo&& info );
 
         TestCase withName( std::string const& _newName ) const;
 
@@ -78,8 +79,7 @@
 
     TestCase makeTestCase(  ITestInvoker* testCase,
                             std::string const& className,
-                            std::string const& name,
-                            std::string const& description,
+                            NameAndTags const& nameAndTags,
                             SourceLineInfo const& lineInfo );
 }
 
diff --git a/include/internal/catch_test_case_registry_impl.cpp b/include/internal/catch_test_case_registry_impl.cpp
index 89c7239..a6b7f57 100644
--- a/include/internal/catch_test_case_registry_impl.cpp
+++ b/include/internal/catch_test_case_registry_impl.cpp
@@ -28,7 +28,7 @@
                 break;
             case RunTests::InRandomOrder:
                 seedRng( config );
-                RandomNumberGenerator::shuffle( sorted );
+                std::shuffle( sorted.begin(), sorted.end(), rng() );
                 break;
             case RunTests::InDeclarationOrder:
                 // already in declaration order
@@ -96,7 +96,7 @@
         m_testAsFunction();
     }
 
-    std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+    std::string extractClassName( StringRef const& classOrQualifiedMethodName ) {
         std::string className = classOrQualifiedMethodName;
         if( startsWith( className, '&' ) )
         {
diff --git a/include/internal/catch_test_case_registry_impl.h b/include/internal/catch_test_case_registry_impl.h
index ad45e5a..8dc5b0f 100644
--- a/include/internal/catch_test_case_registry_impl.h
+++ b/include/internal/catch_test_case_registry_impl.h
@@ -22,7 +22,7 @@
     class TestCase;
     struct IConfig;
 
-    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases ); 
+    std::vector<TestCase> sortTests( IConfig const& config, std::vector<TestCase> const& unsortedTestCases );
     bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config );
 
     void enforceNoDuplicateTestCases( std::vector<TestCase> const& functions );
@@ -58,7 +58,7 @@
     };
 
 
-    std::string extractClassName( std::string const& classOrQualifiedMethodName );
+    std::string extractClassName( StringRef const& classOrQualifiedMethodName );
 
     ///////////////////////////////////////////////////////////////////////////
 
diff --git a/include/internal/catch_test_case_tracker.cpp b/include/internal/catch_test_case_tracker.cpp
index 66da89e..210f273 100644
--- a/include/internal/catch_test_case_tracker.cpp
+++ b/include/internal/catch_test_case_tracker.cpp
@@ -10,7 +10,7 @@
 #include "catch_enforce.h"
 
 #include <algorithm>
-#include <assert.h>
+#include <cassert>
 #include <stdexcept>
 #include <memory>
 #include <sstream>
@@ -69,14 +69,6 @@
     }
 
 
-
-    TrackerBase::TrackerHasName::TrackerHasName( NameAndLocation const& nameAndLocation ) : m_nameAndLocation( nameAndLocation ) {}
-    bool TrackerBase::TrackerHasName::operator ()( ITrackerPtr const& tracker ) const {
-        return
-            tracker->nameAndLocation().name == m_nameAndLocation.name &&
-            tracker->nameAndLocation().location == m_nameAndLocation.location;
-    }
-
     TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent )
     :   m_nameAndLocation( nameAndLocation ),
         m_ctx( ctx ),
@@ -105,7 +97,12 @@
     }
 
     ITrackerPtr TrackerBase::findChild( NameAndLocation const& nameAndLocation ) {
-        auto it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( nameAndLocation ) );
+        auto it = std::find_if( m_children.begin(), m_children.end(),
+            [&nameAndLocation]( ITrackerPtr const& tracker ){
+                return
+                    tracker->nameAndLocation().location == nameAndLocation.location &&
+                    tracker->nameAndLocation().name == nameAndLocation.name;
+            } );
         return( it != m_children.end() )
             ? *it
             : nullptr;
@@ -124,7 +121,7 @@
     }
 
     bool TrackerBase::isSectionTracker() const { return false; }
-    bool TrackerBase::isIndexTracker() const { return false; }
+    bool TrackerBase::isGeneratorTracker() const { return false; }
 
     void TrackerBase::open() {
         m_runState = Executing;
@@ -193,6 +190,17 @@
         }
     }
 
+    bool SectionTracker::isComplete() const {
+        bool complete = true;
+
+        if ((m_filters.empty() || m_filters[0] == "") ||
+             std::find(m_filters.begin(), m_filters.end(),
+                       m_nameAndLocation.name) != m_filters.end())
+            complete = TrackerBase::isComplete();
+        return complete;
+
+    }
+
     bool SectionTracker::isSectionTracker() const { return true; }
 
     SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation ) {
@@ -230,55 +238,11 @@
             m_filters.insert( m_filters.end(), ++filters.begin(), filters.end() );
     }
 
-    IndexTracker::IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size )
-    :   TrackerBase( nameAndLocation, ctx, parent ),
-        m_size( size )
-    {}
-
-    bool IndexTracker::isIndexTracker() const { return true; }
-
-    IndexTracker& IndexTracker::acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size ) {
-        std::shared_ptr<IndexTracker> tracker;
-
-        ITracker& currentTracker = ctx.currentTracker();
-        if( ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) {
-            assert( childTracker );
-            assert( childTracker->isIndexTracker() );
-            tracker = std::static_pointer_cast<IndexTracker>( childTracker );
-        }
-        else {
-            tracker = std::make_shared<IndexTracker>( nameAndLocation, ctx, &currentTracker, 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 IndexTracker::index() const { return m_index; }
-
-    void IndexTracker::moveNext() {
-        m_index++;
-        m_children.clear();
-    }
-
-    void IndexTracker::close() {
-        TrackerBase::close();
-        if( m_runState == CompletedSuccessfully && m_index < m_size-1 )
-            m_runState = Executing;
-    }
-
 } // namespace TestCaseTracking
 
 using TestCaseTracking::ITracker;
 using TestCaseTracking::TrackerContext;
 using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
 
 } // namespace Catch
 
diff --git a/include/internal/catch_test_case_tracker.h b/include/internal/catch_test_case_tracker.h
index a4b0440..1727600 100644
--- a/include/internal/catch_test_case_tracker.h
+++ b/include/internal/catch_test_case_tracker.h
@@ -54,7 +54,7 @@
 
         // Debug/ checking
         virtual bool isSectionTracker() const = 0;
-        virtual bool isIndexTracker() const = 0;
+        virtual bool isGeneratorTracker() const = 0;
     };
 
     class TrackerContext {
@@ -95,13 +95,6 @@
             Failed
         };
 
-        class TrackerHasName {
-            NameAndLocation m_nameAndLocation;
-        public:
-            TrackerHasName( NameAndLocation const& nameAndLocation );
-            bool operator ()( ITrackerPtr const& tracker ) const;
-        };
-
         using Children = std::vector<ITrackerPtr>;
         NameAndLocation m_nameAndLocation;
         TrackerContext& m_ctx;
@@ -127,7 +120,7 @@
         void openChild() override;
 
         bool isSectionTracker() const override;
-        bool isIndexTracker() const override;
+        bool isGeneratorTracker() const override;
 
         void open();
 
@@ -147,6 +140,8 @@
 
         bool isSectionTracker() const override;
 
+        bool isComplete() const override;
+
         static SectionTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation );
 
         void tryOpen();
@@ -155,28 +150,11 @@
         void addNextFilters( std::vector<std::string> const& filters );
     };
 
-    class IndexTracker : public TrackerBase {
-        int m_size;
-        int m_index = -1;
-    public:
-        IndexTracker( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent, int size );
-
-        bool isIndexTracker() const override;
-        void close() override;
-
-        static IndexTracker& acquire( TrackerContext& ctx, NameAndLocation const& nameAndLocation, int size );
-
-        int index() const;
-
-        void moveNext();
-    };
-
 } // namespace TestCaseTracking
 
 using TestCaseTracking::ITracker;
 using TestCaseTracking::TrackerContext;
 using TestCaseTracking::SectionTracker;
-using TestCaseTracking::IndexTracker;
 
 } // namespace Catch
 
diff --git a/include/internal/catch_test_registry.cpp b/include/internal/catch_test_registry.cpp
index 0f6c83e..248bee4 100644
--- a/include/internal/catch_test_registry.cpp
+++ b/include/internal/catch_test_registry.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "catch_test_registry.h"
+#include "catch_compiler_capabilities.h"
 #include "catch_test_case_registry_impl.h"
 #include "catch_interfaces_registry_hub.h"
 
@@ -15,23 +16,22 @@
         return new(std::nothrow) TestInvokerAsFunction( testAsFunction );
     }
 
-    NameAndTags::NameAndTags( StringRef name_ , StringRef tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
+    NameAndTags::NameAndTags( StringRef const& name_ , StringRef const& tags_ ) noexcept : name( name_ ), tags( tags_ ) {}
 
-    AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
-        CATCH_INTERNAL_TRY {
+    AutoReg::AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept {
+        CATCH_TRY {
             getMutableRegistryHub()
                     .registerTest(
                         makeTestCase(
                             invoker,
                             extractClassName( classOrMethod ),
-                            nameAndTags.name,
-                            nameAndTags.tags,
+                            nameAndTags,
                             lineInfo));
-        } CATCH_INTERNAL_CATCH_ALL() {
+        } CATCH_CATCH_ALL {
             // Do not throw when constructing global objects, instead register the exception to be processed later
             getMutableRegistryHub().registerStartupException();
         }
     }
-    
+
     AutoReg::~AutoReg() = default;
 }
diff --git a/include/internal/catch_test_registry.h b/include/internal/catch_test_registry.h
index 8400101..0e7b53d 100644
--- a/include/internal/catch_test_registry.h
+++ b/include/internal/catch_test_registry.h
@@ -12,6 +12,9 @@
 #include "catch_interfaces_testcase.h"
 #include "catch_compiler_capabilities.h"
 #include "catch_stringref.h"
+#include "catch_type_traits.hpp"
+#include "catch_preprocessor.hpp"
+#include "catch_meta.hpp"
 
 namespace Catch {
 
@@ -35,13 +38,13 @@
 }
 
 struct NameAndTags {
-    NameAndTags( StringRef name_ = StringRef(), StringRef tags_ = StringRef() ) noexcept;
+    NameAndTags( StringRef const& name_ = StringRef(), StringRef const& tags_ = StringRef() ) noexcept;
     StringRef name;
     StringRef tags;
 };
 
 struct AutoReg : NonCopyable {
-    AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
+    AutoReg( ITestInvoker* invoker, SourceLineInfo const& lineInfo, StringRef const& classOrMethod, NameAndTags const& nameAndTags ) noexcept;
     ~AutoReg();
 };
 
@@ -52,19 +55,30 @@
         static void TestName()
     #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
         namespace{                        \
-            struct TestName : ClassName { \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
                 void test();              \
             };                            \
         }                                 \
         void TestName::test()
-
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION( TestName, ... )  \
+        template<typename TestType>                                             \
+        static void TestName()
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... )    \
+        namespace{                                                                                  \
+            template<typename TestType>                                                             \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) {     \
+                void test();                                                                        \
+            };                                                                                      \
+        }                                                                                           \
+        template<typename TestType>                                                                 \
+        void TestName::test()
 #endif
 
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
         static void TestName(); \
         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
-        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
         static void TestName()
     #define INTERNAL_CATCH_TESTCASE( ... ) \
@@ -80,7 +94,7 @@
     #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
         namespace{ \
-            struct TestName : ClassName{ \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
                 void test(); \
             }; \
             Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
@@ -93,8 +107,151 @@
     ///////////////////////////////////////////////////////////////////////////////
     #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
         CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
-        Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, "", Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
+        Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
         CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS
 
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, ... )\
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        template<typename TestType> \
+        static void TestFunc();\
+        namespace {\
+            template<typename...Types> \
+            struct TestName{\
+                template<typename...Ts> \
+                TestName(Ts...names){\
+                    CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+                    using expander = int[];\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+                }\
+            };\
+            INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, __VA_ARGS__) \
+        }\
+        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+        template<typename TestType> \
+        static void TestFunc()
+
+#if defined(CATCH_CPP17_OR_GREATER)
+#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>,"Duplicate type detected in declaration of template test case");
+#else
+#define CATCH_INTERNAL_CHECK_UNIQUE_TYPES(...) static_assert(Catch::is_unique<__VA_ARGS__>::value,"Duplicate type detected in declaration of template test case");
+#endif
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestName, Name, ...)\
+        static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+            TestName<CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)>(CATCH_REC_LIST_UD(INTERNAL_CATCH_TEMPLATE_UNIQUE_NAME,Name, __VA_ARGS__));\
+            return 0;\
+        }();
+
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, TmplTypes, TypesList) \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS                      \
+        template<typename TestType> static void TestFuncName();       \
+        namespace {                                                   \
+            template<typename... Types>                               \
+            struct TestName {                                         \
+                TestName() {                                          \
+                    CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)       \
+                    int index = 0;                                    \
+                    using expander = int[];                           \
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\
+                }                                                     \
+            };                                                        \
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
+                using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)> \
+                            ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestName>::type; \
+                TestInit();                                           \
+                return 0;                                             \
+            }();                                                      \
+        }                                                             \
+        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS                    \
+        template<typename TestType>                                   \
+        static void TestFuncName()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ),Name,Tags,__VA_ARGS__)
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, ... ) \
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        namespace{ \
+            template<typename TestType> \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+                void test();\
+            };\
+            template<typename...Types> \
+            struct TestNameClass{\
+                template<typename...Ts> \
+                TestNameClass(Ts...names){\
+                    CATCH_INTERNAL_CHECK_UNIQUE_TYPES(CATCH_REC_LIST(INTERNAL_CATCH_REMOVE_PARENS, __VA_ARGS__)) \
+                    using expander = int[];\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ names, Tags } ), 0)... };/* NOLINT */ \
+                }\
+            };\
+            INTERNAL_CATCH_TEMPLATE_REGISTRY_INITIATE(TestNameClass, Name, __VA_ARGS__)\
+        }\
+        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS\
+        template<typename TestType> \
+        void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+        INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, __VA_ARGS__ ) )
+#endif
+
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, TmplTypes, TypesList)\
+        CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
+        template<typename TestType> \
+            struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
+                void test();\
+            };\
+        namespace {\
+            template<typename...Types>\
+            struct TestNameClass{\
+                TestNameClass(){\
+                    CATCH_INTERNAL_CHECK_UNIQUE_TYPES(Types...)\
+                    int index = 0;\
+                    using expander = int[];\
+                    constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
+                    constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
+                    constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
+                    (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \
+                }\
+            };\
+            static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
+                using TestInit = Catch::combine<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>\
+                            ::with_types<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(TypesList)>::into<TestNameClass>::type;\
+                TestInit();\
+                return 0;\
+            }(); \
+        }\
+        CATCH_INTERNAL_UNSUPPRESS_GLOBALS_WARNINGS \
+        template<typename TestType> \
+        void TestName<TestType>::test()
+
+#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+        INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ )
+#else
+    #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
+        INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, __VA_ARGS__ ) )
+#endif
 
 #endif // TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
diff --git a/include/internal/catch_timer.cpp b/include/internal/catch_timer.cpp
index b9ae688..ca383a2 100644
--- a/include/internal/catch_timer.cpp
+++ b/include/internal/catch_timer.cpp
@@ -10,32 +10,44 @@
 
 #include <chrono>
 
+static const uint64_t nanosecondsInSecond = 1000000000;
+
 namespace Catch {
 
     auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
         return std::chrono::duration_cast<std::chrono::nanoseconds>( std::chrono::high_resolution_clock::now().time_since_epoch() ).count();
     }
 
-    auto estimateClockResolution() -> uint64_t {
-        uint64_t sum = 0;
-        static const uint64_t iterations = 1000000;
+    namespace {
+        auto estimateClockResolution() -> uint64_t {
+            uint64_t sum = 0;
+            static const uint64_t iterations = 1000000;
 
-        for( std::size_t i = 0; i < iterations; ++i ) {
+            auto startTime = getCurrentNanosecondsSinceEpoch();
 
-            uint64_t ticks;
-            uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
-            do {
-                ticks = getCurrentNanosecondsSinceEpoch();
+            for( std::size_t i = 0; i < iterations; ++i ) {
+
+                uint64_t ticks;
+                uint64_t baseTicks = getCurrentNanosecondsSinceEpoch();
+                do {
+                    ticks = getCurrentNanosecondsSinceEpoch();
+                } while( ticks == baseTicks );
+
+                auto delta = ticks - baseTicks;
+                sum += delta;
+
+                // If we have been calibrating for over 3 seconds -- the clock
+                // is terrible and we should move on.
+                // TBD: How to signal that the measured resolution is probably wrong?
+                if (ticks > startTime + 3 * nanosecondsInSecond) {
+                    return sum / ( i + 1u );
+                }
             }
-            while( ticks == baseTicks );
 
-            auto delta = ticks - baseTicks;
-            sum += delta;
+            // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
+            // - and potentially do more iterations if there's a high variance.
+            return sum/iterations;
         }
-
-        // We're just taking the mean, here. To do better we could take the std. dev and exclude outliers
-        // - and potentially do more iterations if there's a high variance.
-        return sum/iterations;
     }
     auto getEstimatedClockResolution() -> uint64_t {
         static auto s_resolution = estimateClockResolution();
diff --git a/include/internal/catch_to_string.hpp b/include/internal/catch_to_string.hpp
new file mode 100644
index 0000000..3e2b587
--- /dev/null
+++ b/include/internal/catch_to_string.hpp
@@ -0,0 +1,28 @@
+/*
+ *  Created by Martin on 9/5/2018.
+ *
+ *  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_CATCH_TO_STRING_H_INCLUDED
+#define TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
+
+#include <string>
+
+#include "catch_compiler_capabilities.h"
+#include "catch_stream.h"
+
+namespace Catch {
+    template <typename T>
+    std::string to_string(T const& t) {
+#if defined(CATCH_CONFIG_CPP11_TO_STRING)
+        return std::to_string(t);
+#else
+        ReusableStringStream rss;
+        rss << t;
+        return rss.str();
+#endif
+    }
+} // end namespace Catch
+
+#endif // TWOBLUECUBES_CATCH_TO_STRING_H_INCLUDED
diff --git a/include/internal/catch_tostring.cpp b/include/internal/catch_tostring.cpp
index a9f7735..b857d3f 100644
--- a/include/internal/catch_tostring.cpp
+++ b/include/internal/catch_tostring.cpp
@@ -20,6 +20,7 @@
 #include "catch_tostring.h"
 #include "catch_interfaces_config.h"
 #include "catch_context.h"
+#include "catch_polyfills.hpp"
 
 #include <cmath>
 #include <iomanip>
@@ -68,7 +69,7 @@
 
 template<typename T>
 std::string fpToString( T value, int precision ) {
-    if (std::isnan(value)) {
+    if (Catch::isnan(value)) {
         return "nan";
     }
 
@@ -116,14 +117,11 @@
     return s;
 }
 
-std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
-    std::string s;
-    s.reserve(wstr.size());
-    for (auto c : wstr) {
-        s += (c <= 0xff) ? static_cast<char>(c) : '?';
-    }
-    return ::Catch::Detail::stringify(s);
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::string_view>::convert(std::string_view str) {
+    return ::Catch::Detail::stringify(std::string{ str });
 }
+#endif
 
 std::string StringMaker<char const*>::convert(char const* str) {
     if (str) {
@@ -139,6 +137,23 @@
         return{ "{null string}" };
     }
 }
+
+#ifdef CATCH_CONFIG_WCHAR
+std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
+    std::string s;
+    s.reserve(wstr.size());
+    for (auto c : wstr) {
+        s += (c <= 0xff) ? static_cast<char>(c) : '?';
+    }
+    return ::Catch::Detail::stringify(s);
+}
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
+    return StringMaker<std::wstring>::convert(std::wstring(str));
+}
+# endif
+
 std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
     if (str) {
         return ::Catch::Detail::stringify(std::wstring{ str });
@@ -153,6 +168,7 @@
         return{ "{null string}" };
     }
 }
+#endif
 
 
 std::string StringMaker<int>::convert(int value) {
@@ -190,7 +206,7 @@
     return b ? "true" : "false";
 }
 
-std::string StringMaker<char>::convert(char value) {
+std::string StringMaker<signed char>::convert(signed char value) {
     if (value == '\r') {
         return "'\\r'";
     } else if (value == '\f') {
@@ -207,8 +223,8 @@
         return chstr;
     }
 }
-std::string StringMaker<signed char>::convert(signed char c) {
-    return ::Catch::Detail::stringify(static_cast<char>(c));
+std::string StringMaker<char>::convert(char c) {
+    return ::Catch::Detail::stringify(static_cast<signed char>(c));
 }
 std::string StringMaker<unsigned char>::convert(unsigned char c) {
     return ::Catch::Detail::stringify(static_cast<char>(c));
@@ -227,12 +243,11 @@
 
 std::string ratio_string<std::atto>::symbol() { return "a"; }
 std::string ratio_string<std::femto>::symbol() { return "f"; }
-std::string  ratio_string<std::pico>::symbol() { return "p"; }
-std::string  ratio_string<std::nano>::symbol() { return "n"; }
+std::string ratio_string<std::pico>::symbol() { return "p"; }
+std::string ratio_string<std::nano>::symbol() { return "n"; }
 std::string ratio_string<std::micro>::symbol() { return "u"; }
 std::string ratio_string<std::milli>::symbol() { return "m"; }
 
-
 } // end namespace Catch
 
 #if defined(__clang__)
diff --git a/include/internal/catch_tostring.h b/include/internal/catch_tostring.h
index 1e644a9..13a43b0 100644
--- a/include/internal/catch_tostring.h
+++ b/include/internal/catch_tostring.h
@@ -13,8 +13,13 @@
 #include <cstddef>
 #include <type_traits>
 #include <string>
+#include "catch_compiler_capabilities.h"
 #include "catch_stream.h"
 
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+#include <string_view>
+#endif
+
 #ifdef __OBJC__
 #include "catch_objc_arc.hpp"
 #endif
@@ -24,15 +29,7 @@
 #pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
 #endif
 
-
-// We need a dummy global operator<< so we can bring it into Catch namespace later
-struct Catch_global_namespace_dummy {};
-std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
-
 namespace Catch {
-    // Bring in operator<< from global namespace into Catch namespace
-    using ::operator<<;
-
     namespace Detail {
 
         extern const std::string unprintableString;
@@ -61,14 +58,38 @@
         std::string convertUnknownEnumToString( E e );
 
         template<typename T>
-        typename std::enable_if<!std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& ) {
+        typename std::enable_if<
+            !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
+        std::string>::type convertUnstreamable( T const& ) {
             return Detail::unprintableString;
         }
         template<typename T>
-        typename std::enable_if<std::is_enum<T>::value, std::string>::type convertUnstreamable( T const& value ) {
+        typename std::enable_if<
+            !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
+         std::string>::type convertUnstreamable(T const& ex) {
+            return ex.what();
+        }
+
+
+        template<typename T>
+        typename std::enable_if<
+            std::is_enum<T>::value
+        , std::string>::type convertUnstreamable( T const& value ) {
             return convertUnknownEnumToString( value );
         }
 
+#if defined(_MANAGED)
+        //! Convert a CLR string to a utf8 std::string
+        template<typename T>
+        std::string clrReferenceToString( T^ ref ) {
+            if (ref == nullptr)
+                return std::string("null");
+            auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
+            cli::pin_ptr<System::Byte> p = &bytes[0];
+            return std::string(reinterpret_cast<char const *>(p), bytes->Length);
+        }
+#endif
+
     } // namespace Detail
 
 
@@ -80,7 +101,9 @@
         typename std::enable_if<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert(const Fake& value) {
                 ReusableStringStream rss;
-                rss << value;
+                // NB: call using the function-like syntax to avoid ambiguity with
+                // user-defined templated operator<< under clang.
+                rss.operator<<(value);
                 return rss.str();
         }
 
@@ -88,7 +111,11 @@
         static
         typename std::enable_if<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>::type
             convert( const Fake& value ) {
-                return Detail::convertUnstreamable( value );
+#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
+            return Detail::convertUnstreamable(value);
+#else
+            return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
+#endif
         }
     };
 
@@ -106,6 +133,13 @@
             return ::Catch::Detail::stringify(static_cast<typename std::underlying_type<E>::type>(e));
         }
 
+#if defined(_MANAGED)
+        template <typename T>
+        std::string stringify( T^ e ) {
+            return ::Catch::StringMaker<T^>::convert(e);
+        }
+#endif
+
     } // namespace Detail
 
     // Some predefined specializations
@@ -114,10 +148,13 @@
     struct StringMaker<std::string> {
         static std::string convert(const std::string& str);
     };
+
+#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
     template<>
-    struct StringMaker<std::wstring> {
-        static std::string convert(const std::wstring& wstr);
+    struct StringMaker<std::string_view> {
+        static std::string convert(std::string_view str);
     };
+#endif
 
     template<>
     struct StringMaker<char const *> {
@@ -127,6 +164,20 @@
     struct StringMaker<char *> {
         static std::string convert(char * str);
     };
+
+#ifdef CATCH_CONFIG_WCHAR
+    template<>
+    struct StringMaker<std::wstring> {
+        static std::string convert(const std::wstring& wstr);
+    };
+
+# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
+    template<>
+    struct StringMaker<std::wstring_view> {
+        static std::string convert(std::wstring_view str);
+    };
+# endif
+
     template<>
     struct StringMaker<wchar_t const *> {
         static std::string convert(wchar_t const * str);
@@ -135,23 +186,26 @@
     struct StringMaker<wchar_t *> {
         static std::string convert(wchar_t * str);
     };
+#endif
 
+    // TBD: Should we use `strnlen` to ensure that we don't go out of the buffer,
+    //      while keeping string semantics?
     template<int SZ>
     struct StringMaker<char[SZ]> {
-        static std::string convert(const char* str) {
+        static std::string convert(char const* str) {
             return ::Catch::Detail::stringify(std::string{ str });
         }
     };
     template<int SZ>
     struct StringMaker<signed char[SZ]> {
-        static std::string convert(const char* str) {
-            return ::Catch::Detail::stringify(std::string{ str });
+        static std::string convert(signed char const* str) {
+            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
         }
     };
     template<int SZ>
     struct StringMaker<unsigned char[SZ]> {
-        static std::string convert(const char* str) {
-            return ::Catch::Detail::stringify(std::string{ str });
+        static std::string convert(unsigned char const* str) {
+            return ::Catch::Detail::stringify(std::string{ reinterpret_cast<char const *>(str) });
         }
     };
 
@@ -235,6 +289,15 @@
         }
     };
 
+#if defined(_MANAGED)
+    template <typename T>
+    struct StringMaker<T^> {
+        static std::string convert( T^ ref ) {
+            return ::Catch::Detail::clrReferenceToString(ref);
+        }
+    };
+#endif
+
     namespace Detail {
         template<typename InputIterator>
         std::string rangeToString(InputIterator first, InputIterator last) {
@@ -283,7 +346,9 @@
 #if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
 #  define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
 #  define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
 #  define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER
+#  define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
 #endif
 
 // Separate std::pair specialization
@@ -305,6 +370,24 @@
 }
 #endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
 
+#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
+#include <optional>
+namespace Catch {
+    template<typename T>
+    struct StringMaker<std::optional<T> > {
+        static std::string convert(const std::optional<T>& optional) {
+            ReusableStringStream rss;
+            if (optional.has_value()) {
+                rss << ::Catch::Detail::stringify(*optional);
+            } else {
+                rss << "{ }";
+            }
+            return rss.str();
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
+
 // Separate std::tuple specialization
 #if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
 #include <tuple>
@@ -347,6 +430,34 @@
 }
 #endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
 
+#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
+#include <variant>
+namespace Catch {
+    template<>
+    struct StringMaker<std::monostate> {
+        static std::string convert(const std::monostate&) {
+            return "{ }";
+        }
+    };
+
+    template<typename... Elements>
+    struct StringMaker<std::variant<Elements...>> {
+        static std::string convert(const std::variant<Elements...>& variant) {
+            if (variant.valueless_by_exception()) {
+                return "{valueless variant}";
+            } else {
+                return std::visit(
+                    [](const auto& value) {
+                        return ::Catch::Detail::stringify(value);
+                    },
+                    variant
+                );
+            }
+        }
+    };
+}
+#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
+
 namespace Catch {
     struct not_this_one {}; // Tag type for detecting which begin/ end are being selected
 
@@ -364,6 +475,13 @@
             !std::is_same<decltype(end(std::declval<T>())), not_this_one>::value;
     };
 
+#if defined(_MANAGED) // Managed types are never ranges
+    template <typename T>
+    struct is_range<T^> {
+        static const bool value = false;
+    };
+#endif
+
     template<typename Range>
     std::string rangeToString( Range const& range ) {
         return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
diff --git a/include/internal/catch_totals.h b/include/internal/catch_totals.h
index 9507582..5692728 100644
--- a/include/internal/catch_totals.h
+++ b/include/internal/catch_totals.h
@@ -32,7 +32,7 @@
 
         Totals delta( Totals const& prevTotals ) const;
 
-
+        int error = 0;
         Counts assertions;
         Counts testCases;
     };
diff --git a/include/internal/catch_type_traits.hpp b/include/internal/catch_type_traits.hpp
new file mode 100644
index 0000000..8edb1ec
--- /dev/null
+++ b/include/internal/catch_type_traits.hpp
@@ -0,0 +1,40 @@
+/*
+ *  Created by Jozef on 12/11/2018.
+ *  Copyright 2017 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_CATCH_TYPE_TRAITS_HPP_INCLUDED
+#define TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
+
+#include <type_traits>
+
+namespace Catch{
+
+#ifdef CATCH_CPP17_OR_GREATER
+	template <typename...>
+	inline constexpr auto is_unique = std::true_type{};
+
+	template <typename T, typename... Rest>
+	inline constexpr auto is_unique<T, Rest...> = std::bool_constant<
+		(!std::is_same_v<T, Rest> && ...) && is_unique<Rest...>
+	>{};
+#else
+
+template <typename...>
+struct is_unique : std::true_type{};
+
+template <typename T0, typename T1, typename... Rest>
+struct is_unique<T0, T1, Rest...> : std::integral_constant
+<bool,
+     !std::is_same<T0, T1>::value 
+     && is_unique<T0, Rest...>::value 
+     && is_unique<T1, Rest...>::value
+>{};
+
+#endif
+}
+
+#endif // TWOBLUECUBES_CATCH_TYPE_TRAITS_HPP_INCLUDED
diff --git a/include/internal/catch_uncaught_exceptions.cpp b/include/internal/catch_uncaught_exceptions.cpp
index 0e47a04..b990ccd 100644
--- a/include/internal/catch_uncaught_exceptions.cpp
+++ b/include/internal/catch_uncaught_exceptions.cpp
@@ -12,7 +12,6 @@
 
 namespace Catch {
     bool uncaught_exceptions() {
-// https://github.com/catchorg/Catch2/issues/1162
 #if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
         return std::uncaught_exceptions() > 0;
 #else
diff --git a/include/internal/catch_version.cpp b/include/internal/catch_version.cpp
index fc196d9..a1d08b2 100644
--- a/include/internal/catch_version.cpp
+++ b/include/internal/catch_version.cpp
@@ -37,7 +37,7 @@
     }
 
     Version const& libraryVersion() {
-        static Version version( 2, 1, 1, "", 0 );
+        static Version version( 2, 7, 0, "", 0 );
         return version;
     }
 
diff --git a/include/internal/catch_xmlwriter.cpp b/include/internal/catch_xmlwriter.cpp
index a3316f4..5354efa 100644
--- a/include/internal/catch_xmlwriter.cpp
+++ b/include/internal/catch_xmlwriter.cpp
@@ -7,51 +7,147 @@
 
 #include "catch_xmlwriter.h"
 
+#include "catch_enforce.h"
+
 #include <iomanip>
 
+using uchar = unsigned char;
+
 namespace Catch {
 
+namespace {
+
+    size_t trailingBytes(unsigned char c) {
+        if ((c & 0xE0) == 0xC0) {
+            return 2;
+        }
+        if ((c & 0xF0) == 0xE0) {
+            return 3;
+        }
+        if ((c & 0xF8) == 0xF0) {
+            return 4;
+        }
+        CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+    }
+
+    uint32_t headerValue(unsigned char c) {
+        if ((c & 0xE0) == 0xC0) {
+            return c & 0x1F;
+        }
+        if ((c & 0xF0) == 0xE0) {
+            return c & 0x0F;
+        }
+        if ((c & 0xF8) == 0xF0) {
+            return c & 0x07;
+        }
+        CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
+    }
+
+    void hexEscapeChar(std::ostream& os, unsigned char c) {
+        std::ios_base::fmtflags f(os.flags());
+        os << "\\x"
+            << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
+            << static_cast<int>(c);
+        os.flags(f);
+    }
+
+} // anonymous namespace
+
     XmlEncode::XmlEncode( std::string const& str, ForWhat forWhat )
     :   m_str( str ),
         m_forWhat( forWhat )
     {}
 
     void XmlEncode::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 << "&lt;"; break;
-                case '&':   os << "&amp;"; break;
+        for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
+            uchar c = m_str[idx];
+            switch (c) {
+            case '<':   os << "&lt;"; break;
+            case '&':   os << "&amp;"; break;
 
-                case '>':
-                    // See: http://www.w3.org/TR/xml/#syntax
-                    if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' )
-                        os << "&gt;";
-                    else
-                        os << c;
+            case '>':
+                // See: http://www.w3.org/TR/xml/#syntax
+                if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
+                    os << "&gt;";
+                else
+                    os << c;
+                break;
+
+            case '\"':
+                if (m_forWhat == ForAttributes)
+                    os << "&quot;";
+                else
+                    os << c;
+                break;
+
+            default:
+                // Check for control characters and invalid utf-8
+
+                // Escape control characters in standard ascii
+                // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
+                if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
+                    hexEscapeChar(os, c);
                     break;
+                }
 
-                case '\"':
-                    if( m_forWhat == ForAttributes )
-                        os << "&quot;";
-                    else
-                        os << c;
+                // Plain ASCII: Write it to stream
+                if (c < 0x7F) {
+                    os << c;
                     break;
+                }
 
-                default:
-                    // Escape control chars - based on contribution by @espenalb in PR #465 and
-                    // by @mrpi PR #588
-                    if ( ( c >= 0 && c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) {
-                        // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
-                        os << "\\x" << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
-                           << static_cast<int>( c );
-                    }
-                    else
-                        os << c;
+                // UTF-8 territory
+                // Check if the encoding is valid and if it is not, hex escape bytes.
+                // Important: We do not check the exact decoded values for validity, only the encoding format
+                // First check that this bytes is a valid lead byte:
+                // This means that it is not encoded as 1111 1XXX
+                // Or as 10XX XXXX
+                if (c <  0xC0 ||
+                    c >= 0xF8) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+
+                auto encBytes = trailingBytes(c);
+                // Are there enough bytes left to avoid accessing out-of-bounds memory?
+                if (idx + encBytes - 1 >= m_str.size()) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+                // The header is valid, check data
+                // The next encBytes bytes must together be a valid utf-8
+                // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
+                bool valid = true;
+                uint32_t value = headerValue(c);
+                for (std::size_t n = 1; n < encBytes; ++n) {
+                    uchar nc = m_str[idx + n];
+                    valid &= ((nc & 0xC0) == 0x80);
+                    value = (value << 6) | (nc & 0x3F);
+                }
+
+                if (
+                    // Wrong bit pattern of following bytes
+                    (!valid) ||
+                    // Overlong encodings
+                    (value < 0x80) ||
+                    (0x80 <= value && value < 0x800   && encBytes > 2) ||
+                    (0x800 < value && value < 0x10000 && encBytes > 3) ||
+                    // Encoded value out of range
+                    (value >= 0x110000)
+                    ) {
+                    hexEscapeChar(os, c);
+                    break;
+                }
+
+                // If we got here, this is in fact a valid(ish) utf-8 sequence
+                for (std::size_t n = 0; n < encBytes; ++n) {
+                    os << m_str[idx + n];
+                }
+                idx += encBytes - 1;
+                break;
             }
         }
     }
diff --git a/include/internal/catch_xmlwriter.h b/include/internal/catch_xmlwriter.h
index 76456f9..c4b1c03 100644
--- a/include/internal/catch_xmlwriter.h
+++ b/include/internal/catch_xmlwriter.h
@@ -56,7 +56,7 @@
 
         XmlWriter( std::ostream& os = Catch::cout() );
         ~XmlWriter();
-        
+
         XmlWriter( XmlWriter const& ) = delete;
         XmlWriter& operator=( XmlWriter const& ) = delete;
 
diff --git a/include/reporters/catch_reporter_bases.cpp b/include/reporters/catch_reporter_bases.cpp
index c2059b5..ce3553e 100644
--- a/include/reporters/catch_reporter_bases.cpp
+++ b/include/reporters/catch_reporter_bases.cpp
@@ -13,7 +13,7 @@
 #include <cstring>
 #include <cfloat>
 #include <cstdio>
-#include <assert.h>
+#include <cassert>
 #include <memory>
 
 namespace Catch {
@@ -30,13 +30,13 @@
         // + 1 for null terminator
         const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
         char buffer[maxDoubleSize];
- 
+
         // Save previous errno, to prevent sprintf from overwriting it
         ErrnoGuard guard;
 #ifdef _MSC_VER
         sprintf_s(buffer, "%.3f", duration);
 #else
-        sprintf(buffer, "%.3f", duration);
+        std::sprintf(buffer, "%.3f", duration);
 #endif
         return std::string(buffer);
     }
@@ -45,6 +45,10 @@
     TestEventListenerBase::TestEventListenerBase(ReporterConfig const & _config)
         :StreamingReporterBase(_config) {}
 
+    std::set<Verbosity> TestEventListenerBase::getSupportedVerbosities() {
+        return { Verbosity::Quiet, Verbosity::Normal, Verbosity::High };
+    }
+
     void TestEventListenerBase::assertionStarting(AssertionInfo const &) {}
 
     bool TestEventListenerBase::assertionEnded(AssertionStats const &) {
diff --git a/include/reporters/catch_reporter_bases.hpp b/include/reporters/catch_reporter_bases.hpp
index 4c03d0e..4a27db6 100644
--- a/include/reporters/catch_reporter_bases.hpp
+++ b/include/reporters/catch_reporter_bases.hpp
@@ -8,13 +8,14 @@
 #ifndef TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
 #define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
 
+#include "../internal/catch_enforce.h"
 #include "../internal/catch_interfaces_reporter.h"
 
 #include <algorithm>
 #include <cstring>
 #include <cfloat>
 #include <cstdio>
-#include <assert.h>
+#include <cassert>
 #include <memory>
 #include <ostream>
 
@@ -33,7 +34,7 @@
         {
             m_reporterPrefs.shouldRedirectStdOut = false;
             if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
-                Exception::doThrow( std::domain_error( "Verbosity level not supported by this reporter" ) );
+                CATCH_ERROR( "Verbosity level not supported by this reporter" );
         }
 
         ReporterPreferences getPreferences() const override {
@@ -148,7 +149,7 @@
         {
             m_reporterPrefs.shouldRedirectStdOut = false;
             if( !DerivedT::getSupportedVerbosities().count( m_config->verbosity() ) )
-                Exception::doThrow( std::domain_error( "Verbosity level not supported by this reporter" ) );
+                CATCH_ERROR( "Verbosity level not supported by this reporter" );
         }
         ~CumulativeReporterBase() override = default;
 
@@ -216,7 +217,7 @@
             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;
@@ -265,6 +266,8 @@
     struct TestEventListenerBase : StreamingReporterBase<TestEventListenerBase> {
         TestEventListenerBase( ReporterConfig const& _config );
 
+        static std::set<Verbosity> getSupportedVerbosities();
+
         void assertionStarting(AssertionInfo const&) override;
         bool assertionEnded(AssertionStats const&) override;
     };
diff --git a/include/reporters/catch_reporter_compact.cpp b/include/reporters/catch_reporter_compact.cpp
index caf4d3f..65f7026 100644
--- a/include/reporters/catch_reporter_compact.cpp
+++ b/include/reporters/catch_reporter_compact.cpp
@@ -245,9 +245,7 @@
         }
 
         ReporterPreferences CompactReporter::getPreferences() const {
-            ReporterPreferences prefs;
-            prefs.shouldRedirectStdOut = false;
-            return prefs;
+            return m_reporterPrefs;
         }
 
         void CompactReporter::noMatchingTestCases( std::string const& spec ) {
diff --git a/include/reporters/catch_reporter_console.cpp b/include/reporters/catch_reporter_console.cpp
index 54b62cd..76dc9ec 100644
--- a/include/reporters/catch_reporter_console.cpp
+++ b/include/reporters/catch_reporter_console.cpp
@@ -111,8 +111,6 @@
     void print() const {
         printSourceInfo();
         if (stats.totals.assertions.total() > 0) {
-            if (result.isOk())
-                stream << '\n';
             printResultType();
             printOriginalExpression();
             printReconstructedExpression();
@@ -247,7 +245,7 @@
         case Unit::Nanoseconds:
             return "ns";
         case Unit::Microseconds:
-            return "µs";
+            return "us";
         case Unit::Milliseconds:
             return "ms";
         case Unit::Seconds:
diff --git a/include/reporters/catch_reporter_junit.cpp b/include/reporters/catch_reporter_junit.cpp
index d133b70..7e97ee3 100644
--- a/include/reporters/catch_reporter_junit.cpp
+++ b/include/reporters/catch_reporter_junit.cpp
@@ -13,7 +13,7 @@
 #include "../internal/catch_tostring.h"
 #include "../internal/catch_reporter_registrars.hpp"
 
-#include <assert.h>
+#include <cassert>
 #include <sstream>
 #include <ctime>
 #include <algorithm>
@@ -62,6 +62,7 @@
             xml( _config.stream() )
         {
             m_reporterPrefs.shouldRedirectStdOut = true;
+            m_reporterPrefs.shouldReportAllAssertions = true;
         }
 
     JunitReporter::~JunitReporter() {}
@@ -75,6 +76,13 @@
     void JunitReporter::testRunStarting( TestRunInfo const& runInfo )  {
         CumulativeReporterBase::testRunStarting( runInfo );
         xml.startElement( "testsuites" );
+        if( m_config->rngSeed() != 0 ) {
+            xml.startElement( "properties" );
+            xml.scopedElement( "property" )
+                .writeAttribute( "name", "random-seed" )
+                .writeAttribute( "value", m_config->rngSeed() );
+            xml.endElement();
+        }
     }
 
     void JunitReporter::testGroupStarting( GroupInfo const& groupInfo ) {
diff --git a/include/reporters/catch_reporter_listening.cpp b/include/reporters/catch_reporter_listening.cpp
new file mode 100644
index 0000000..9ddae2f
--- /dev/null
+++ b/include/reporters/catch_reporter_listening.cpp
@@ -0,0 +1,142 @@
+/*
+ *  Created by Phil on 5/08/2015.
+ *  Copyright 2015 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)
+ */
+
+ #include "catch_reporter_listening.h"
+#include <cassert>
+
+namespace Catch {
+
+    ListeningReporter::ListeningReporter() {
+        // We will assume that listeners will always want all assertions
+        m_preferences.shouldReportAllAssertions = true;
+    }
+
+    void ListeningReporter::addListener( IStreamingReporterPtr&& listener ) {
+        m_listeners.push_back( std::move( listener ) );
+    }
+
+    void ListeningReporter::addReporter(IStreamingReporterPtr&& reporter) {
+        assert(!m_reporter && "Listening reporter can wrap only 1 real reporter");
+        m_reporter = std::move( reporter );
+        m_preferences.shouldRedirectStdOut = m_reporter->getPreferences().shouldRedirectStdOut;
+    }
+
+    ReporterPreferences ListeningReporter::getPreferences() const {
+        return m_preferences;
+    }
+
+    std::set<Verbosity> ListeningReporter::getSupportedVerbosities() {
+        return std::set<Verbosity>{ };
+    }
+
+
+    void ListeningReporter::noMatchingTestCases( std::string const& spec ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->noMatchingTestCases( spec );
+        }
+        m_reporter->noMatchingTestCases( spec );
+    }
+
+    void ListeningReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkStarting( benchmarkInfo );
+        }
+        m_reporter->benchmarkStarting( benchmarkInfo );
+    }
+    void ListeningReporter::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->benchmarkEnded( benchmarkStats );
+        }
+        m_reporter->benchmarkEnded( benchmarkStats );
+    }
+
+    void ListeningReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunStarting( testRunInfo );
+        }
+        m_reporter->testRunStarting( testRunInfo );
+    }
+
+    void ListeningReporter::testGroupStarting( GroupInfo const& groupInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupStarting( groupInfo );
+        }
+        m_reporter->testGroupStarting( groupInfo );
+    }
+
+
+    void ListeningReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseStarting( testInfo );
+        }
+        m_reporter->testCaseStarting( testInfo );
+    }
+
+    void ListeningReporter::sectionStarting( SectionInfo const& sectionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionStarting( sectionInfo );
+        }
+        m_reporter->sectionStarting( sectionInfo );
+    }
+
+    void ListeningReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->assertionStarting( assertionInfo );
+        }
+        m_reporter->assertionStarting( assertionInfo );
+    }
+
+    // The return value indicates if the messages buffer should be cleared:
+    bool ListeningReporter::assertionEnded( AssertionStats const& assertionStats ) {
+        for( auto const& listener : m_listeners ) {
+            static_cast<void>( listener->assertionEnded( assertionStats ) );
+        }
+        return m_reporter->assertionEnded( assertionStats );
+    }
+
+    void ListeningReporter::sectionEnded( SectionStats const& sectionStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->sectionEnded( sectionStats );
+        }
+        m_reporter->sectionEnded( sectionStats );
+    }
+
+    void ListeningReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testCaseEnded( testCaseStats );
+        }
+        m_reporter->testCaseEnded( testCaseStats );
+    }
+
+    void ListeningReporter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testGroupEnded( testGroupStats );
+        }
+        m_reporter->testGroupEnded( testGroupStats );
+    }
+
+    void ListeningReporter::testRunEnded( TestRunStats const& testRunStats ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->testRunEnded( testRunStats );
+        }
+        m_reporter->testRunEnded( testRunStats );
+    }
+
+
+    void ListeningReporter::skipTest( TestCaseInfo const& testInfo ) {
+        for ( auto const& listener : m_listeners ) {
+            listener->skipTest( testInfo );
+        }
+        m_reporter->skipTest( testInfo );
+    }
+
+    bool ListeningReporter::isMulti() const {
+        return true;
+    }
+
+} // end namespace Catch
diff --git a/include/reporters/catch_reporter_multi.h b/include/reporters/catch_reporter_listening.h
similarity index 84%
rename from include/reporters/catch_reporter_multi.h
rename to include/reporters/catch_reporter_listening.h
index 985d442..dddd7a5 100644
--- a/include/reporters/catch_reporter_multi.h
+++ b/include/reporters/catch_reporter_listening.h
@@ -11,12 +11,17 @@
 
 namespace Catch {
 
-    class MultipleReporters : public IStreamingReporter {
+    class ListeningReporter : public IStreamingReporter {
         using Reporters = std::vector<IStreamingReporterPtr>;
-        Reporters m_reporters;
+        Reporters m_listeners;
+        IStreamingReporterPtr m_reporter = nullptr;
+        ReporterPreferences m_preferences;
 
     public:
-        void add( IStreamingReporterPtr&& reporter );
+        ListeningReporter();
+
+        void addListener( IStreamingReporterPtr&& listener );
+        void addReporter( IStreamingReporterPtr&& reporter );
 
     public: // IStreamingReporter
 
diff --git a/include/reporters/catch_reporter_multi.cpp b/include/reporters/catch_reporter_multi.cpp
deleted file mode 100644
index 23bb160..0000000
--- a/include/reporters/catch_reporter_multi.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- *  Created by Phil on 5/08/2015.
- *  Copyright 2015 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)
- */
-
- #include "catch_reporter_multi.h"
-
-namespace Catch {
-
-    void MultipleReporters::add( IStreamingReporterPtr&& reporter ) {
-        m_reporters.push_back( std::move( reporter ) );
-    }
-
-    ReporterPreferences MultipleReporters::getPreferences() const {
-        return m_reporters[0]->getPreferences();
-    }
-
-    std::set<Verbosity> MultipleReporters::getSupportedVerbosities() {
-        return std::set<Verbosity>{ };
-    }
-
-
-    void MultipleReporters::noMatchingTestCases( std::string const& spec ) {
-        for( auto const& reporter : m_reporters )
-            reporter->noMatchingTestCases( spec );
-    }
-
-    void MultipleReporters::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->benchmarkStarting( benchmarkInfo );
-    }
-    void MultipleReporters::benchmarkEnded( BenchmarkStats const& benchmarkStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->benchmarkEnded( benchmarkStats );
-    }
-
-    void MultipleReporters::testRunStarting( TestRunInfo const& testRunInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testRunStarting( testRunInfo );
-    }
-
-    void MultipleReporters::testGroupStarting( GroupInfo const& groupInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testGroupStarting( groupInfo );
-    }
-
-
-    void MultipleReporters::testCaseStarting( TestCaseInfo const& testInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testCaseStarting( testInfo );
-    }
-
-    void MultipleReporters::sectionStarting( SectionInfo const& sectionInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->sectionStarting( sectionInfo );
-    }
-
-    void MultipleReporters::assertionStarting( AssertionInfo const& assertionInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->assertionStarting( assertionInfo );
-    }
-
-    // The return value indicates if the messages buffer should be cleared:
-    bool MultipleReporters::assertionEnded( AssertionStats const& assertionStats ) {
-        bool clearBuffer = false;
-        for( auto const& reporter : m_reporters )
-            clearBuffer |= reporter->assertionEnded( assertionStats );
-        return clearBuffer;
-    }
-
-    void MultipleReporters::sectionEnded( SectionStats const& sectionStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->sectionEnded( sectionStats );
-    }
-
-    void MultipleReporters::testCaseEnded( TestCaseStats const& testCaseStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testCaseEnded( testCaseStats );
-    }
-
-    void MultipleReporters::testGroupEnded( TestGroupStats const& testGroupStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testGroupEnded( testGroupStats );
-    }
-
-    void MultipleReporters::testRunEnded( TestRunStats const& testRunStats ) {
-        for( auto const& reporter : m_reporters )
-            reporter->testRunEnded( testRunStats );
-    }
-
-
-    void MultipleReporters::skipTest( TestCaseInfo const& testInfo ) {
-        for( auto const& reporter : m_reporters )
-            reporter->skipTest( testInfo );
-    }
-
-    bool MultipleReporters::isMulti() const {
-        return true;
-    }
-
-} // end namespace Catch
diff --git a/include/reporters/catch_reporter_tap.hpp b/include/reporters/catch_reporter_tap.hpp
index edb75b5..1bfe4f5 100644
--- a/include/reporters/catch_reporter_tap.hpp
+++ b/include/reporters/catch_reporter_tap.hpp
@@ -26,13 +26,11 @@
         ~TAPReporter() override;
 
         static std::string getDescription() {
-            return "Reports test results in TAP format, suitable for test harneses";
+            return "Reports test results in TAP format, suitable for test harnesses";
         }
 
         ReporterPreferences getPreferences() const override {
-            ReporterPreferences prefs;
-            prefs.shouldRedirectStdOut = false;
-            return prefs;
+            return m_reporterPrefs;
         }
 
         void noMatchingTestCases( std::string const& spec ) override {
@@ -44,9 +42,9 @@
         bool assertionEnded( AssertionStats const& _assertionStats ) override {
             ++counter;
 
+            stream << "# " << currentTestCaseInfo->name << std::endl;
             AssertionPrinter printer( stream, _assertionStats, counter );
             printer.print();
-            stream << " # " << currentTestCaseInfo->name ;
 
             stream << std::endl;
             return true;
diff --git a/include/reporters/catch_reporter_teamcity.hpp b/include/reporters/catch_reporter_teamcity.hpp
index ddd0d92..eca2885 100644
--- a/include/reporters/catch_reporter_teamcity.hpp
+++ b/include/reporters/catch_reporter_teamcity.hpp
@@ -97,12 +97,12 @@
                     case ResultWas::Ok:
                     case ResultWas::Info:
                     case ResultWas::Warning:
-                        Exception::doThrow( std::domain_error( "Internal error in TeamCity reporter" ) );
+                        CATCH_ERROR( "Internal error in TeamCity reporter" );
                     // These cases are here to prevent compiler warnings
                     case ResultWas::Unknown:
                     case ResultWas::FailureBit:
                     case ResultWas::Exception:
-                        Exception::doThrow( std::domain_error( "Not implemented" ) );
+                        CATCH_ERROR( "Not implemented" );
                 }
                 if( assertionStats.infoMessages.size() == 1 )
                     msg << " with message:";
diff --git a/include/reporters/catch_reporter_xml.cpp b/include/reporters/catch_reporter_xml.cpp
index b721d44..902014c 100644
--- a/include/reporters/catch_reporter_xml.cpp
+++ b/include/reporters/catch_reporter_xml.cpp
@@ -24,6 +24,7 @@
         m_xml(_config.stream())
     {
         m_reporterPrefs.shouldRedirectStdOut = true;
+        m_reporterPrefs.shouldReportAllAssertions = true;
     }
 
     XmlReporter::~XmlReporter() = default;
@@ -54,6 +55,9 @@
         m_xml.startElement( "Catch" );
         if( !m_config->name().empty() )
             m_xml.writeAttribute( "name", m_config->name() );
+        if( m_config->rngSeed() != 0 )
+            m_xml.scopedElement( "Randomness" )
+                .writeAttribute( "seed", m_config->rngSeed() );
     }
 
     void XmlReporter::testGroupStarting( GroupInfo const& groupInfo ) {
@@ -80,8 +84,7 @@
         StreamingReporterBase::sectionStarting( sectionInfo );
         if( m_sectionDepth++ > 0 ) {
             m_xml.startElement( "Section" )
-                .writeAttribute( "name", trim( sectionInfo.name ) )
-                .writeAttribute( "description", sectionInfo.description );
+                .writeAttribute( "name", trim( sectionInfo.name ) );
             writeSourceInfo( sectionInfo.lineInfo );
             m_xml.ensureTagClosed();
         }
diff --git a/misc/SelfTest.vcxproj.user b/misc/SelfTest.vcxproj.user
new file mode 100644
index 0000000..ffffc57
--- /dev/null
+++ b/misc/SelfTest.vcxproj.user
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+    <ClCompile>
+      <UseFullPaths>false</UseFullPaths>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+    <ClCompile>
+      <UseFullPaths>false</UseFullPaths>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+    <ClCompile>
+      <UseFullPaths>false</UseFullPaths>
+    </ClCompile>
+  </ItemDefinitionGroup>
+  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+    <ClCompile>
+      <UseFullPaths>false</UseFullPaths>
+    </ClCompile>
+  </ItemDefinitionGroup>
+</Project>
diff --git a/misc/appveyorBuildConfigurationScript.bat b/misc/appveyorBuildConfigurationScript.bat
index 27efcd1..f07bb70 100644
--- a/misc/appveyorBuildConfigurationScript.bat
+++ b/misc/appveyorBuildConfigurationScript.bat
@@ -1,13 +1,22 @@
-@REM  # In debug build, we want to
-@REM  # 1) Prebuild memcheck redirecter
-@REM  # 2) Regenerate single header include for examples
-@REM  # 3) Enable building examples
+SETLOCAL EnableDelayedExpansion
+
+@REM  # Possibilities:
+@REM  # Debug build + coverage
+@REM  # Debug build + examples
+@REM  # Debug build +   ---
+@REM  # Release build
 if "%CONFIGURATION%"=="Debug" (
-  python scripts\generateSingleHeader.py
-  cmake -Hmisc -Bbuild-misc -A%PLATFORM%
-  cmake --build build-misc
-  cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=ON -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind
+  if "%coverage%"=="1" (
+    @REM # coverage needs to build the special helper as well as the main
+    cmake -Hmisc -Bbuild-misc -A%PLATFORM% || exit /b !ERRORLEVEL!
+    cmake --build build-misc || exit /b !ERRORLEVEL!
+    cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DMEMORYCHECK_COMMAND=build-misc\Debug\CoverageHelper.exe -DMEMORYCHECK_COMMAND_OPTIONS=--sep-- -DMEMORYCHECK_TYPE=Valgrind || exit /b !ERRORLEVEL! || exit /b !ERRORLEVEL!
+  ) else (
+    @REM # We know that coverage is 0
+    python scripts\generateSingleHeader.py || exit /b !ERRORLEVEL!
+    cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% -DCATCH_BUILD_EXAMPLES=%examples% -DCATCH_BUILD_EXTRA_TESTS=%examples% || exit /b !ERRORLEVEL!
+  )
 )
 if "%CONFIGURATION%"=="Release" (
-  cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain%
+  cmake -H. -BBuild -A%PLATFORM% -DUSE_WMAIN=%wmain% || exit /b !ERRORLEVEL!
 )
diff --git a/misc/appveyorTestRunScript.bat b/misc/appveyorTestRunScript.bat
index fdcc2ce..c129d99 100644
--- a/misc/appveyorTestRunScript.bat
+++ b/misc/appveyorTestRunScript.bat
@@ -1,9 +1,15 @@
+SETLOCAL EnableDelayedExpansion
+
 cd Build
 if "%CONFIGURATION%"=="Debug" (
-  ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck
-  python ..\misc\appveyorMergeCoverageScript.py
-  codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN%
+  if "%coverage%"=="1" (
+    ctest -j 2 -C %CONFIGURATION% -D ExperimentalMemCheck || exit /b !ERRORLEVEL!
+    python ..\misc\appveyorMergeCoverageScript.py || exit /b !ERRORLEVEL!
+    codecov --root .. --no-color --disable gcov -f cobertura.xml -t %CODECOV_TOKEN% || exit /b !ERRORLEVEL!
+  ) else (
+    ctest -j 2 -C %CONFIGURATION% || exit /b !ERRORLEVEL!
+  )
 )
 if "%CONFIGURATION%"=="Release" (
-  ctest -j 2 -C %CONFIGURATION%
+  ctest -j 2 -C %CONFIGURATION% || exit /b !ERRORLEVEL!
 )
diff --git a/misc/coverage-helper.cpp b/misc/coverage-helper.cpp
index 9783d69..a664383 100644
--- a/misc/coverage-helper.cpp
+++ b/misc/coverage-helper.cpp
@@ -9,6 +9,38 @@
 #include <string>
 #include <vector>
 
+std::string escape_arg(const std::string& arg) {
+    if (arg.empty() == false &&
+        arg.find_first_of(" \t\n\v\"") == arg.npos) {
+        return arg;
+    }
+
+    std::string escaped;
+    escaped.push_back('"');
+    for (auto it = arg.begin(); ; ++it) {
+        int num_backslashes = 0;
+
+        while (it != arg.end() && *it == '\\') {
+            ++it;
+            ++num_backslashes;
+        }
+
+        if (it == arg.end()) {
+            escaped.append(num_backslashes * 2, '\\');
+            break;
+        } else if (*it == '"') {
+            escaped.append(num_backslashes * 2 + 1, '\\');
+            escaped.push_back(*it);
+        } else {
+            escaped.append(num_backslashes, '\\');
+            escaped.push_back(*it);
+        }
+    }
+    escaped.push_back('"');
+
+    return escaped;
+}
+
 
 void create_empty_file(std::string const& path) {
     std::ofstream ofs(path);
@@ -60,8 +92,9 @@
 void exec_cmd(std::string const& cmd, int log_num, std::string const& path) {
     std::array<char, 128> buffer;
 #if defined(_WIN32)
+    // cmd has already been escaped outside this function.
     auto real_cmd = "OpenCppCoverage --export_type binary:cov-report" + std::to_string(log_num)
-        + ".bin --quiet " + "--sources " + path + " --cover_children -- " + cmd;
+        + ".bin --quiet " + "--sources " + escape_arg(path) + " --cover_children -- " + cmd;
     std::cout << "=== Marker ===: Cmd: " << real_cmd << '\n';
     std::shared_ptr<FILE> pipe(_popen(real_cmd.c_str(), "r"), _pclose);
 #else // Just for testing, in the real world we will always work under WIN32
@@ -91,10 +124,15 @@
     assert(sep - begin(args) == 2 && "Structure differs from expected!");
 
     auto num = parse_log_file_arg(args[1]);
-
+    
     auto cmdline = std::accumulate(++sep, end(args), std::string{}, [] (const std::string& lhs, const std::string& rhs) {
-        return lhs + ' ' + rhs;
+        return lhs + ' ' + escape_arg(rhs);
     });
 
-    exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));
+    try {
+        return exec_cmd(cmdline, num, windowsify_path(catch_path(args[0])));
+    } catch (std::exception const& ex) {
+        std::cerr << "Helper failed with: '" << ex.what() << "'\n";
+        return 12;
+    }
 }
diff --git a/misc/installOpenCppCoverage.ps1 b/misc/installOpenCppCoverage.ps1
index 9dbffca..d277a55 100644
--- a/misc/installOpenCppCoverage.ps1
+++ b/misc/installOpenCppCoverage.ps1
@@ -1,5 +1,5 @@
-# Downloads are done from the oficial github release page links
-$downloadUrl = "https://github.com/OpenCppCoverage/OpenCppCoverage/releases/download/release-0.9.6.1/OpenCppCoverageSetup-x64-0.9.6.1.exe"
+# Downloads are done from the official github release page links
+$downloadUrl = "https://github.com/OpenCppCoverage/OpenCppCoverage/releases/download/release-0.9.7.0/OpenCppCoverageSetup-x64-0.9.7.0.exe"
 $installerPath = [System.IO.Path]::Combine($Env:USERPROFILE, "Downloads", "OpenCppCoverageSetup.exe")
 
 if(-Not (Test-Path $installerPath)) {
diff --git a/projects/Benchmark/BenchMain.cpp b/projects/Benchmark/BenchMain.cpp
deleted file mode 100644
index 32ef4ed..0000000
--- a/projects/Benchmark/BenchMain.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-/*
- *  Created by Martin on 16/01/2017.
- *
- *  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)
- */
-
-#define CATCH_CONFIG_MAIN
-#include "catch.hpp"
diff --git a/projects/Benchmark/StringificationBench.cpp b/projects/Benchmark/StringificationBench.cpp
deleted file mode 100644
index 765b4e9..0000000
--- a/projects/Benchmark/StringificationBench.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- *  Created by Martin on 16/01/2017.
- *
- *  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 "catch.hpp"
-
-#include <vector>
-
-///////////////////////////////////////////////////////////////////////////////
-TEST_CASE("Successful tests -- REQUIRE", "[Success]") {
-    const std::size_t sz = 1 * 1024 * 1024;
-
-
-    std::vector<std::size_t> vec; vec.reserve(sz);
-    for (std::size_t i = 0; i < sz; ++i){
-        vec.push_back(i);
-        REQUIRE(vec.back() == i);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-TEST_CASE("Successful tests -- CHECK", "[Success]") {
-    const std::size_t sz = 1 * 1024 * 1024;
-
-
-    std::vector<std::size_t> vec; vec.reserve(sz);
-    for (std::size_t i = 0; i < sz; ++i){
-        vec.push_back(i);
-        CHECK(vec.back() == i);
-    }
-}
-
-///////////////////////////////////////////////////////////////////////////////
-TEST_CASE("Unsuccessful tests -- CHECK", "[Failure]") {
-    const std::size_t sz = 1024 * 1024;
-
-
-    std::vector<std::size_t> vec; vec.reserve(sz);
-    for (std::size_t i = 0; i < sz; ++i){
-        vec.push_back(i);
-        CHECK(vec.size() == i);
-    }
-}
diff --git a/projects/Benchmark/readme.txt b/projects/Benchmark/readme.txt
deleted file mode 100644
index c4d2fab..0000000
--- a/projects/Benchmark/readme.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-This is very much a work in progress.
-The past results are standardized to a developer's machine,
-the benchmarking script is basic and there are only 3 benchmarks,
-but this should get better in time. For now, at least there is something to go by.
diff --git a/projects/Benchmark/results/2017-01-14T21-53-49-e3659cdddd43ba4df9e4846630be6a6a7bd85a07.result b/projects/Benchmark/results/2017-01-14T21-53-49-e3659cdddd43ba4df9e4846630be6a6a7bd85a07.result
deleted file mode 100644
index 4b6fc65..0000000
--- a/projects/Benchmark/results/2017-01-14T21-53-49-e3659cdddd43ba4df9e4846630be6a6a7bd85a07.result
+++ /dev/null
@@ -1,3 +0,0 @@
-Successful tests -- CHECK: median: 3.38116 (s), stddev: 0.11567366292001534 (s)
-Successful tests -- REQUIRE: median: 3.479955 (s), stddev: 0.16295972890734556 (s)
-Unsuccessful tests -- CHECK: median: 1.966895 (s), stddev: 0.06323488524716572 (s)
diff --git a/projects/Benchmark/results/2017-01-14T21-59-08-a1e9b841ff500b2f39ccfd4193ae450cb653da05.result b/projects/Benchmark/results/2017-01-14T21-59-08-a1e9b841ff500b2f39ccfd4193ae450cb653da05.result
deleted file mode 100644
index 98c8460..0000000
--- a/projects/Benchmark/results/2017-01-14T21-59-08-a1e9b841ff500b2f39ccfd4193ae450cb653da05.result
+++ /dev/null
@@ -1,3 +0,0 @@
-Successful tests -- CHECK: median: 1.30312 (s), stddev: 0.08759818557862176 (s)
-Successful tests -- REQUIRE: median: 1.341535 (s), stddev: 0.1479193390143576 (s)
-Unsuccessful tests -- CHECK: median: 1.967755 (s), stddev: 0.07921104121269959 (s)
diff --git a/projects/Benchmark/results/2017-01-15T09-35-14-3b98a0166f7b7196eba2ad518174d1a77165166d.result b/projects/Benchmark/results/2017-01-15T09-35-14-3b98a0166f7b7196eba2ad518174d1a77165166d.result
deleted file mode 100644
index fe6366b..0000000
--- a/projects/Benchmark/results/2017-01-15T09-35-14-3b98a0166f7b7196eba2ad518174d1a77165166d.result
+++ /dev/null
@@ -1,3 +0,0 @@
-Successful tests -- CHECK: median: 1.2982 (s), stddev: 0.019540648829214084 (s)
-Successful tests -- REQUIRE: median: 1.30102 (s), stddev: 0.014758430547392974 (s)
-Unsuccessful tests -- CHECK: median: