From e1498deaa8ade23230bb0a5e320154138065e259 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Tue, 15 Dec 2015 19:51:31 +0000 Subject: [PATCH 01/37] [skip ci] Windows: * read Boost version from AppVeyor.yml * init submodules from build-local.bat --- scripts/build-local.bat | 33 ++++++++++++++++++++++++++++++--- scripts/parse-appveyor-yml.ps1 | 7 +++++++ 2 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 scripts/parse-appveyor-yml.ps1 diff --git a/scripts/build-local.bat b/scripts/build-local.bat index 5d9affc7f..2dbbd1371 100644 --- a/scripts/build-local.bat +++ b/scripts/build-local.bat @@ -8,14 +8,39 @@ SET APPVEYOR_REPO_COMMIT_MESSAGE=this is a [build appveyor] test SET APPVEYOR=true ::comment this to get complete AppVeyor behaviour SET LOCAL_BUILD_DONT_SKIP_TESTS=true - -SET MAPNIK_GIT=3.0.5 -SET BOOST_VERSION=59 SET FASTBUILD=1 + +FOR /F "tokens=1 usebackq" %%i in (`powershell .\scripts\parse-appveyor-yml.ps1`) DO SET BOOST_VERSION=%%i +ECHO BOOST_VERSION found in appveyor.yml^: %BOOST_VERSION% +IF "%BOOST_VERSION%"=="0" ECHO BOOST_VERSION not valid && SET ERRORLEVEL=1 && GOTO ERROR + + +:: OVERRIDE PARAMETERS >>>>>>>> +:NEXT-ARG + +IF '%1'=='' GOTO ARGS-DONE +ECHO setting %1 +SET %1 +SHIFT +GOTO NEXT-ARG + +:ARGS-DONE +::<<<<< OVERRIDE PARAMETERS + + SET configuration=Release SET msvs_toolset=14 SET platform=x64 SET APPVEYOR_BUILD_FOLDER=%CD% + + + +ECHO pulling test data +CALL git submodule update --init +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +ECHO pulling test data, DONE + +SET TIME_START_LOCAL_BUILD=%TIME% CALL scripts\build-appveyor.bat IF %ERRORLEVEL% NEQ 0 GOTO ERROR @@ -28,5 +53,7 @@ SET EL=%ERRORLEVEL% :DONE ECHO =========== DONE %~f0 =========== +ECHO build started^: %TIME_START_LOCAL_BUILD% +ECHO build finished^: %TIME% EXIT /b %EL% diff --git a/scripts/parse-appveyor-yml.ps1 b/scripts/parse-appveyor-yml.ps1 new file mode 100644 index 000000000..f87ae7e3a --- /dev/null +++ b/scripts/parse-appveyor-yml.ps1 @@ -0,0 +1,7 @@ +$ErrorActionPreference = 'Stop' +$boost_version='0' +Get-Content .\appveyor.yml | + foreach { + if ($_ -match "BOOST_VERSION: "){ $boost_version = $_.split()[-1] } + } +Write-Host $boost_version From d75fd12eab60dcc4c7f703b5c1e03f5309c14670 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Wed, 16 Dec 2015 10:56:05 +0000 Subject: [PATCH 02/37] Windows: output pagefile size on AppVeyor (compiler out of heapspace) --- scripts/appveyor-system-info.ps1 | 13 +++++++++++++ scripts/build-appveyor.bat | 1 + 2 files changed, 14 insertions(+) create mode 100644 scripts/appveyor-system-info.ps1 diff --git a/scripts/appveyor-system-info.ps1 b/scripts/appveyor-system-info.ps1 new file mode 100644 index 000000000..e061c98e2 --- /dev/null +++ b/scripts/appveyor-system-info.ps1 @@ -0,0 +1,13 @@ +$SystemManaged = Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile} +$total_physicalmem = gwmi Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)} +$physical_mem = get-ciminstance -class 'cim_physicalmemory' | % { $_.Capacity/1024/1024} + +$PF =gwmi Win32_PageFileUsage +$PageFileLocation = $PF.Name; +$PageFileSize = $PF.AllocatedBaseSize + +Write-Host "physical memory : $physical_mem" +Write-Host "total physical memory : $total_physicalmem" +Write-Host "page file system managed : $SystemManaged" +Write-Host "page file location : $PageFileLocation" +Write-Host "page file size : $PageFileSize" \ No newline at end of file diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat index 0cadb5ef8..4bfbe9b22 100644 --- a/scripts/build-appveyor.bat +++ b/scripts/build-appveyor.bat @@ -8,6 +8,7 @@ ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS% ECHO RAM [MB]^: powershell "get-ciminstance -class 'cim_physicalmemory' | %% { $_.Capacity/1024/1024}" IF %ERRORLEVEL% NEQ 0 GOTO ERROR +powershell .\scripts\appveyor-system-info.ps1 ::only build on AppVeyor, if explicitly stated ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE% From 34f7c86caf2f9f990bbaf7f431078f3bd2264daa Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Wed, 16 Dec 2015 11:29:22 +0000 Subject: [PATCH 03/37] AppVeyor: try to increase page file size via powershell --- scripts/appveyor-system-info.ps1 | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/scripts/appveyor-system-info.ps1 b/scripts/appveyor-system-info.ps1 index e061c98e2..662df3451 100644 --- a/scripts/appveyor-system-info.ps1 +++ b/scripts/appveyor-system-info.ps1 @@ -5,9 +5,29 @@ $physical_mem = get-ciminstance -class 'cim_physicalmemory' | % { $_.Capacity/10 $PF =gwmi Win32_PageFileUsage $PageFileLocation = $PF.Name; $PageFileSize = $PF.AllocatedBaseSize +$CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting Write-Host "physical memory : $physical_mem" Write-Host "total physical memory : $total_physicalmem" Write-Host "page file system managed : $SystemManaged" Write-Host "page file location : $PageFileLocation" -Write-Host "page file size : $PageFileSize" \ No newline at end of file +Write-Host "page file size : $PageFileSize" +Write-Host page file min size : $CurrentPageFile.InitialSize +Write-Host "page file max size : $CurrentPageFile.MaximumSize" + +#disable automatically managed page file settings +$c = Get-WmiObject Win32_computersystem -EnableAllPrivileges +if($c.AutomaticManagedPagefile){ + Write-Host disabling managed page file settings + $c.AutomaticManagedPagefile = $false + $c.Put() | Out-Null +} + +$new_page_size=8192 + +if($PageFileSize -lt $new_page_size){ + Write-Host "settings new page file size to $new_page_size" + $CurrentPageFile.InitialSize=$new_page_size + $CurrentPageFile.MaximumSize=$new_page_size + $CurrentPageFile.Put() | Out-Null +} From 1a49fe20fb34669d3527b0f4fca6d38956602932 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Wed, 16 Dec 2015 12:04:35 +0000 Subject: [PATCH 04/37] AppVeyor: set powershell execution policy --- scripts/appveyor-system-info.ps1 | 43 +++++++++++++++++++++++--------- scripts/build-appveyor.bat | 4 +-- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/scripts/appveyor-system-info.ps1 b/scripts/appveyor-system-info.ps1 index 662df3451..1b60c8567 100644 --- a/scripts/appveyor-system-info.ps1 +++ b/scripts/appveyor-system-info.ps1 @@ -1,19 +1,21 @@ -$SystemManaged = Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile} +$PSVersionTable +$PSVersionTable.PSVersion + +$SystemManaged = Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile} $total_physicalmem = gwmi Win32_ComputerSystem | % {[Math]::round($_.TotalPhysicalMemory/1MB,0)} $physical_mem = get-ciminstance -class 'cim_physicalmemory' | % { $_.Capacity/1024/1024} $PF =gwmi Win32_PageFileUsage $PageFileLocation = $PF.Name; $PageFileSize = $PF.AllocatedBaseSize -$CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting -Write-Host "physical memory : $physical_mem" -Write-Host "total physical memory : $total_physicalmem" -Write-Host "page file system managed : $SystemManaged" -Write-Host "page file location : $PageFileLocation" -Write-Host "page file size : $PageFileSize" -Write-Host page file min size : $CurrentPageFile.InitialSize -Write-Host "page file max size : $CurrentPageFile.MaximumSize" +Write-Host "physical memory : "$physical_mem +Write-Host "total physical memory : "$total_physicalmem +Write-Host "page file system managed : "$SystemManaged +Write-Host "page file location : "$PageFileLocation +Write-Host "page file size : "$PageFileSize +Write-Host "InitialSize : "${CurrentPageFile}.InitialSize +Write-Host "MaximumSize : "$CurrentPageFile.MaximumSize #disable automatically managed page file settings $c = Get-WmiObject Win32_computersystem -EnableAllPrivileges @@ -23,11 +25,28 @@ if($c.AutomaticManagedPagefile){ $c.Put() | Out-Null } -$new_page_size=8192 - -if($PageFileSize -lt $new_page_size){ +$new_page_size=18000 +$CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting +if($CurrentPageFile.InitialSize -ne $new_page_size){ Write-Host "settings new page file size to $new_page_size" $CurrentPageFile.InitialSize=$new_page_size $CurrentPageFile.MaximumSize=$new_page_size $CurrentPageFile.Put() | Out-Null } + +Write-Host "new ------------ " +Write-Host "system managed:" (Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}) +Write-Host "page file size:" (gwmi Win32_PageFileUsage).AllocatedBaseSize +Write-Host "InitialSize: "${CurrentPageFile}.InitialSize +Write-Host "MaximumSize: "$CurrentPageFile.MaximumSize + +#list drives +Get-WmiObject -Class Win32_LogicalDisk | + Where-Object {$_.DriveType -ne 5} | + Sort-Object -Property Name | + Select-Object Name, VolumeName, FileSystem, Description, VolumeDirty, ` + @{"Label"="DiskSize(GB)";"Expression"={"{0:N}" -f ($_.Size/1GB) -as [float]}}, ` + @{"Label"="FreeSpace(GB)";"Expression"={"{0:N}" -f ($_.FreeSpace/1GB) -as [float]}}, ` + @{"Label"="%Free";"Expression"={"{0:N}" -f ($_.FreeSpace/$_.Size*100) -as [float]}} | + Format-Table -AutoSize + diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat index 4bfbe9b22..1f332d53b 100644 --- a/scripts/build-appveyor.bat +++ b/scripts/build-appveyor.bat @@ -5,10 +5,10 @@ SET EL=0 ECHO =========== %~f0 =========== ECHO NUMBER_OF_PROCESSORS^: %NUMBER_OF_PROCESSORS% -ECHO RAM [MB]^: -powershell "get-ciminstance -class 'cim_physicalmemory' | %% { $_.Capacity/1024/1024}" +powershell Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy Unrestricted -Force IF %ERRORLEVEL% NEQ 0 GOTO ERROR powershell .\scripts\appveyor-system-info.ps1 +IF %ERRORLEVEL% NEQ 0 GOTO ERROR ::only build on AppVeyor, if explicitly stated ECHO APPVEYOR_REPO_COMMIT_MESSAGE^: %APPVEYOR_REPO_COMMIT_MESSAGE% From eff087c0cfb8c0e8174ab283890b380e3a8ed8c8 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Wed, 16 Dec 2015 14:19:55 +0000 Subject: [PATCH 05/37] [skip ci] Windows: only manipulate page file settings on AppVeyor --- scripts/appveyor-system-info.ps1 | 45 ++++++++++++++++++-------------- 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/scripts/appveyor-system-info.ps1 b/scripts/appveyor-system-info.ps1 index 1b60c8567..550cfb530 100644 --- a/scripts/appveyor-system-info.ps1 +++ b/scripts/appveyor-system-info.ps1 @@ -17,28 +17,33 @@ Write-Host "page file size : "$PageFileSize Write-Host "InitialSize : "${CurrentPageFile}.InitialSize Write-Host "MaximumSize : "$CurrentPageFile.MaximumSize -#disable automatically managed page file settings -$c = Get-WmiObject Win32_computersystem -EnableAllPrivileges -if($c.AutomaticManagedPagefile){ - Write-Host disabling managed page file settings - $c.AutomaticManagedPagefile = $false - $c.Put() | Out-Null -} +if($env:APPVEYOR -eq "true"){ + Write-Host !!!!!!! on AppVeyor: changing page file settings !!!!!!!!!! + #disable automatically managed page file settings + $c = Get-WmiObject Win32_computersystem -EnableAllPrivileges + if($c.AutomaticManagedPagefile){ + Write-Host disabling managed page file settings + $c.AutomaticManagedPagefile = $false + $c.Put() | Out-Null + } -$new_page_size=18000 -$CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting -if($CurrentPageFile.InitialSize -ne $new_page_size){ - Write-Host "settings new page file size to $new_page_size" - $CurrentPageFile.InitialSize=$new_page_size - $CurrentPageFile.MaximumSize=$new_page_size - $CurrentPageFile.Put() | Out-Null -} + $new_page_size=18000 + $CurrentPageFile = Get-WmiObject -Class Win32_PageFileSetting + if($CurrentPageFile.InitialSize -ne $new_page_size){ + Write-Host "setting new page file size to $new_page_size" + $CurrentPageFile.InitialSize=$new_page_size + $CurrentPageFile.MaximumSize=$new_page_size + $CurrentPageFile.Put() | Out-Null + } -Write-Host "new ------------ " -Write-Host "system managed:" (Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}) -Write-Host "page file size:" (gwmi Win32_PageFileUsage).AllocatedBaseSize -Write-Host "InitialSize: "${CurrentPageFile}.InitialSize -Write-Host "MaximumSize: "$CurrentPageFile.MaximumSize + Write-Host "new ------------ " + Write-Host "system managed:" (Get-WmiObject -Class Win32_ComputerSystem | % {$_.AutomaticManagedPagefile}) + Write-Host "page file size:" (gwmi Win32_PageFileUsage).AllocatedBaseSize + Write-Host "InitialSize: "${CurrentPageFile}.InitialSize + Write-Host "MaximumSize: "$CurrentPageFile.MaximumSize +} else { + Write-Host not on AppVeyor, leaving page file as is +} #list drives Get-WmiObject -Class Win32_LogicalDisk | From e3a1108ebd52b2279b8f47336db465bab7180795 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 16 Dec 2015 13:01:56 -0800 Subject: [PATCH 06/37] Add a script to time how long it takes to compile a header inside mapnik --- scripts/time-header | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100755 scripts/time-header diff --git a/scripts/time-header b/scripts/time-header new file mode 100755 index 000000000..97c3c6977 --- /dev/null +++ b/scripts/time-header @@ -0,0 +1,9 @@ +#!/usr/bin/env bash + +set -eu +set -o pipefail + +CXXFLAGS="$(./utils/mapnik-config/mapnik-config --cflags)" +CXX="$(./utils/mapnik-config/mapnik-config --cxx)" +echo "Time taken to compile '$(basename $1)':" +time ${CXX} $1 -I./test -I./deps/agg/include -Ideps -I./include $CXXFLAGS -o /tmp/header.out \ No newline at end of file From ce98a5c81131136cf198db6f24af6cd55ec2626d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 16 Dec 2015 13:17:19 -0800 Subject: [PATCH 07/37] fix header glitches uncovered by time-header script - refs #3208 --- include/mapnik/image_scaling_traits.hpp | 4 +++- include/mapnik/image_util_jpeg.hpp | 2 ++ include/mapnik/{span_image_filter.h => span_image_filter.hpp} | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) rename include/mapnik/{span_image_filter.h => span_image_filter.hpp} (99%) diff --git a/include/mapnik/image_scaling_traits.hpp b/include/mapnik/image_scaling_traits.hpp index 69eec5a05..81ddf54e4 100644 --- a/include/mapnik/image_scaling_traits.hpp +++ b/include/mapnik/image_scaling_traits.hpp @@ -24,7 +24,9 @@ #define MAPNIK_IMAGE_SCALING_TRAITS_HPP // mapnik -#include +#include +#include +#include // agg #include "agg_image_accessors.h" diff --git a/include/mapnik/image_util_jpeg.hpp b/include/mapnik/image_util_jpeg.hpp index b8b213a0c..feb810533 100644 --- a/include/mapnik/image_util_jpeg.hpp +++ b/include/mapnik/image_util_jpeg.hpp @@ -23,6 +23,8 @@ #ifndef MAPNIK_IMAGE_UTIL_JPEG_HPP #define MAPNIK_IMAGE_UTIL_JPEG_HPP +#include + // stl #include #include diff --git a/include/mapnik/span_image_filter.h b/include/mapnik/span_image_filter.hpp similarity index 99% rename from include/mapnik/span_image_filter.h rename to include/mapnik/span_image_filter.hpp index cd843010b..972558ccf 100644 --- a/include/mapnik/span_image_filter.h +++ b/include/mapnik/span_image_filter.hpp @@ -26,6 +26,8 @@ #include "agg_span_image_filter_gray.h" #include "agg_span_image_filter_rgba.h" +#include + #include namespace mapnik From a0719870ab793a975575a6053f0421b33fc8da85 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 16 Dec 2015 14:22:09 -0800 Subject: [PATCH 08/37] remove out of date/unused header --- include/mapnik/geometry_unique.hpp | 82 ------------------------------ 1 file changed, 82 deletions(-) delete mode 100644 include/mapnik/geometry_unique.hpp diff --git a/include/mapnik/geometry_unique.hpp b/include/mapnik/geometry_unique.hpp deleted file mode 100644 index 167822801..000000000 --- a/include/mapnik/geometry_unique.hpp +++ /dev/null @@ -1,82 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 Artem Pavlenko - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - *****************************************************************************/ - -#ifndef MAPNIK_GEOMETRY_UNIQUE_HPP -#define MAPNIK_GEOMETRY_UNIQUE_HPP - -#include -#include -#include - -#include - -namespace mapnik { namespace geometry { - -namespace detail { - -struct geometry_unique -{ - using result_type = void; - - result_type operator() (geometry & geom) const - { - mapnik::util::apply_visitor(*this, geom); - } - - result_type operator() (geometry_collection & collection) const - { - for (auto & geom : collection) - { - (*this)(geom); - } - } - - result_type operator() (line_string & line) const - { - boost::geometry::unique(line); - } - - result_type operator() (polygon & poly) const - { - boost::geometry::unique(poly); - } - - template - result_type operator() (T & geom) const - { - // no-op - } - -}; - -} - -template -inline void unique(GeomType & geom) -{ - static_assert(!std::is_const::value,"mapnik::geometry::unique on const& is invalid"); - detail::geometry_unique()(geom); -} - -}} - -#endif // MAPNIK_GEOMETRY_UNIQUE_HPP From bd21e452d1155c3f14965410625b983224a948a2 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 16 Dec 2015 14:22:36 -0800 Subject: [PATCH 09/37] fix minor header glitches to allow headers to compile standalone --- include/mapnik/image_filter_grammar.hpp | 9 +++++---- include/mapnik/image_null.hpp | 1 + include/mapnik/image_util_png.hpp | 2 ++ include/mapnik/image_view_null.hpp | 2 +- include/mapnik/mapped_memory_cache.hpp | 2 +- include/mapnik/symbolizer_default_values.hpp | 5 +++++ 6 files changed, 15 insertions(+), 6 deletions(-) diff --git a/include/mapnik/image_filter_grammar.hpp b/include/mapnik/image_filter_grammar.hpp index 04ced605b..ef9b6697b 100644 --- a/include/mapnik/image_filter_grammar.hpp +++ b/include/mapnik/image_filter_grammar.hpp @@ -23,16 +23,17 @@ #ifndef MAPNIK_IMAGE_FILITER_GRAMMAR_HPP #define MAPNIK_IMAGE_FILITER_GRAMMAR_HPP +// mapnik +#include +#include +#include + #pragma GCC diagnostic push #include #include #include #pragma GCC diagnostic pop -// mapnik -#include -#include - // stl #include diff --git a/include/mapnik/image_null.hpp b/include/mapnik/image_null.hpp index 67dbbd358..2fc4e32c5 100644 --- a/include/mapnik/image_null.hpp +++ b/include/mapnik/image_null.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include #include //stl diff --git a/include/mapnik/image_util_png.hpp b/include/mapnik/image_util_png.hpp index e02cb4427..8592c4fd4 100644 --- a/include/mapnik/image_util_png.hpp +++ b/include/mapnik/image_util_png.hpp @@ -23,6 +23,8 @@ #ifndef MAPNIK_IMAGE_UTIL_PNG_HPP #define MAPNIK_IMAGE_UTIL_PNG_HPP +#include + // stl #include #include diff --git a/include/mapnik/image_view_null.hpp b/include/mapnik/image_view_null.hpp index 5672c05dd..76ebc5f49 100644 --- a/include/mapnik/image_view_null.hpp +++ b/include/mapnik/image_view_null.hpp @@ -23,7 +23,7 @@ #ifndef MAPNIK_IMAGE_VIEW_NULL_HPP #define MAPNIK_IMAGE_VIEW_NULL_HPP -#include +#include //stl #include diff --git a/include/mapnik/mapped_memory_cache.hpp b/include/mapnik/mapped_memory_cache.hpp index f41c2e803..6b6102c4e 100644 --- a/include/mapnik/mapped_memory_cache.hpp +++ b/include/mapnik/mapped_memory_cache.hpp @@ -28,8 +28,8 @@ #include #include -// boost #include +#include #include #include diff --git a/include/mapnik/symbolizer_default_values.hpp b/include/mapnik/symbolizer_default_values.hpp index b70ea194b..ea5e5c02e 100644 --- a/include/mapnik/symbolizer_default_values.hpp +++ b/include/mapnik/symbolizer_default_values.hpp @@ -24,7 +24,12 @@ #define MAPNIK_SYMBOLIZER_DEFAULT_VALUES_HPP #include +#include +#include +#include +#include #include +#include #include From e0c756ee8d90c9cd1cbc67c8b5e2ce5d7451128a Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 17 Dec 2015 12:03:19 +0000 Subject: [PATCH 10/37] geometry_envelope - add missing linear_ring --- include/mapnik/geometry_envelope_impl.hpp | 23 ++++++++++++++--------- src/geometry_envelope.cpp | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/include/mapnik/geometry_envelope_impl.hpp b/include/mapnik/geometry_envelope_impl.hpp index dbed6aa47..5c39bc386 100644 --- a/include/mapnik/geometry_envelope_impl.hpp +++ b/include/mapnik/geometry_envelope_impl.hpp @@ -41,7 +41,7 @@ struct geometry_envelope { return mapnik::util::apply_visitor(*this, geom); } - + void operator() (mapnik::geometry::geometry_empty const&) const {} template @@ -60,30 +60,36 @@ struct geometry_envelope bool first = true; for (auto const& pt : line) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } } } + template + void operator() (mapnik::geometry::linear_ring const& ring) const + { + (*this)(static_cast const&>(ring)); + } + template void operator() (mapnik::geometry::polygon const& poly) const { bool first = true; for (auto const& pt : poly.exterior_ring) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } @@ -96,12 +102,12 @@ struct geometry_envelope bool first = true; for (auto const& pt : multi_point) { - if (first && !bbox.valid()) + if (first && !bbox.valid()) { bbox.init(pt.x, pt.y, pt.x, pt.y); first = false; } - else + else { bbox.expand_to_include(pt.x, pt.y); } @@ -140,7 +146,7 @@ struct geometry_envelope template mapnik::box2d envelope(T const& geom) -{ +{ box2d bbox; detail::geometry_envelope op(bbox); op(geom); @@ -149,4 +155,3 @@ mapnik::box2d envelope(T const& geom) } // end ns geometry } // end ns mapnik - diff --git a/src/geometry_envelope.cpp b/src/geometry_envelope.cpp index 0aa3466f1..5b3ade6f2 100644 --- a/src/geometry_envelope.cpp +++ b/src/geometry_envelope.cpp @@ -31,6 +31,7 @@ template MAPNIK_DECL mapnik::box2d envelope(mapnik::base_symbolizer_help template MAPNIK_DECL mapnik::box2d envelope(geometry_empty const& geom); template MAPNIK_DECL mapnik::box2d envelope(point const& geom); template MAPNIK_DECL mapnik::box2d envelope(line_string const& geom); +template MAPNIK_DECL mapnik::box2d envelope(linear_ring const& geom); template MAPNIK_DECL mapnik::box2d envelope(polygon const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_point const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_line_string const& geom); @@ -40,6 +41,7 @@ template MAPNIK_DECL mapnik::box2d envelope(geometry_collection template MAPNIK_DECL mapnik::box2d envelope(geometry const& geom); template MAPNIK_DECL mapnik::box2d envelope(point const& geom); template MAPNIK_DECL mapnik::box2d envelope(line_string const& geom); +template MAPNIK_DECL mapnik::box2d envelope(linear_ring const& geom); template MAPNIK_DECL mapnik::box2d envelope(polygon const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_point const& geom); template MAPNIK_DECL mapnik::box2d envelope(multi_line_string const& geom); From 630640ee6c08cff0c071db2be8bf492ad0cbb518 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Wed, 23 Dec 2015 12:48:43 +0100 Subject: [PATCH 11/37] Windows: pull python bindings, too. --- scripts/build-local.bat | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/build-local.bat b/scripts/build-local.bat index 2dbbd1371..e2a822f3d 100644 --- a/scripts/build-local.bat +++ b/scripts/build-local.bat @@ -33,7 +33,13 @@ SET msvs_toolset=14 SET platform=x64 SET APPVEYOR_BUILD_FOLDER=%CD% +IF NOT EXIST bindings\python git clone https://github.com/mapnik/python-mapnik.git bindings/python +IF %ERRORLEVEL% NEQ 0 GOTO ERROR +CD bindings\python & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +git fetch & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +git pull & IF %ERRORLEVEL% NEQ 0 GOTO ERROR +CD ..\.. & IF %ERRORLEVEL% NEQ 0 GOTO ERROR ECHO pulling test data CALL git submodule update --init From dfa62c88d84de39a5f4e6d45f0964e2b38f7d53c Mon Sep 17 00:00:00 2001 From: Blake Thompson Date: Sun, 27 Dec 2015 21:40:10 -0600 Subject: [PATCH 12/37] fix for santize address errors --- SConstruct | 6 ++++++ include/mapnik/json/positions_grammar.hpp | 13 +++++++++++-- plugins/input/pgraster/build.py | 3 +-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/SConstruct b/SConstruct index 05562d9a7..53fe21fc6 100644 --- a/SConstruct +++ b/SConstruct @@ -294,6 +294,7 @@ opts.AddVariables( # Note: setting DEBUG=True will override any custom OPTIMIZATION level BoolVariable('DEBUG', 'Compile a debug version of Mapnik', 'False'), BoolVariable('DEBUG_UNDEFINED', 'Compile a version of Mapnik using clang/llvm undefined behavior asserts', 'False'), + BoolVariable('DEBUG_SANITIZE', 'Compile a version of Mapnik using clang/llvm address sanitation', 'False'), ListVariable('INPUT_PLUGINS','Input drivers to include',DEFAULT_PLUGINS,PLUGINS.keys()), ('WARNING_CXXFLAGS', 'Compiler flags you can set to reduce warning levels which are placed after -Wall.', ''), @@ -1799,6 +1800,11 @@ if not preconfigured: if env['DEBUG_UNDEFINED']: env.Append(CXXFLAGS = '-fsanitize=undefined-trap -fsanitize-undefined-trap-on-error -ftrapv -fwrapv') + if env['DEBUG_SANITIZE']: + env.Append(CXXFLAGS = ['-fsanitize=address']) + env.Append(LINKFLAGS = ['-fsanitize=address']) + + # if requested, sort LIBPATH and CPPPATH one last time before saving... if env['PRIORITIZE_LINKING']: conf.prioritize_paths(silent=True) diff --git a/include/mapnik/json/positions_grammar.hpp b/include/mapnik/json/positions_grammar.hpp index a652e8f59..48121053f 100644 --- a/include/mapnik/json/positions_grammar.hpp +++ b/include/mapnik/json/positions_grammar.hpp @@ -56,7 +56,11 @@ struct set_position_impl template result_type operator() (T0 & coords, T1 const& pos) const { - if (pos) coords = *pos; + if (pos) + { + auto const& p = *pos; + coords = p; + } } }; @@ -66,7 +70,12 @@ struct push_position_impl template result_type operator() (T0 & coords, T1 const& pos) const { - if (pos) coords.push_back(*pos); + if (pos) + { + auto const& p = *pos; + typename T0::value_type p1(p); + coords.emplace_back(p1); + } } }; diff --git a/plugins/input/pgraster/build.py b/plugins/input/pgraster/build.py index 7b859ee5b..7d120e482 100644 --- a/plugins/input/pgraster/build.py +++ b/plugins/input/pgraster/build.py @@ -60,8 +60,7 @@ if env['PLUGIN_LINKING'] == 'shared': SHLIBPREFIX='', SHLIBSUFFIX='.input', source=plugin_sources, - LIBS=libraries, - LINKFLAGS=env['CUSTOM_LDFLAGS']) + LIBS=libraries) # if the plugin links to libmapnik ensure it is built first Depends(TARGET, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) From 9ad6ee299905e418a93a83b2cb730d4dc3cd2ed3 Mon Sep 17 00:00:00 2001 From: Jiri Drbalek Date: Mon, 28 Dec 2015 09:30:46 +0000 Subject: [PATCH 13/37] visual tests: fix vector initialization --- test/visual/runner.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/visual/runner.cpp b/test/visual/runner.cpp index 06ade7779..5ff923172 100644 --- a/test/visual/runner.cpp +++ b/test/visual/runner.cpp @@ -150,7 +150,8 @@ result_list runner::test_all(report_type & report) const result_list runner::test(std::vector const & style_names, report_type & report) const { - std::vector files(style_names.size()); + std::vector files; + files.reserve(style_names.size()); std::transform(style_names.begin(), style_names.end(), std::back_inserter(files), [&](runner::path_type const & name) { From a2b3130d4bcd4df9e684a3a580ae29ac6c89a48c Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 11:43:27 +0000 Subject: [PATCH 14/37] rebase to master (remove spirit-x3 changes) --- .../input/shape/shape_index_featureset.cpp | 24 ++++-- .../input/shape/shape_index_featureset.hpp | 14 +++- plugins/input/shape/shape_io.cpp | 79 +++++++++++++++++++ plugins/input/shape/shape_io.hpp | 2 + plugins/input/shape/shapefile.hpp | 5 ++ utils/shapeindex/shapeindex.cpp | 72 +++++++++++++++-- 6 files changed, 182 insertions(+), 14 deletions(-) diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp index f91d7acf4..0fe625487 100644 --- a/plugins/input/shape/shape_index_featureset.cpp +++ b/plugins/input/shape/shape_index_featureset.cpp @@ -63,12 +63,14 @@ shape_index_featureset::shape_index_featureset(filterT const& filter, if (index) { #if defined(MAPNIK_MEMORY_MAPPED_FILE) - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #else - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #endif } - std::sort(offsets_.begin(), offsets_.end()); + std::sort(offsets_.begin(), offsets_.end(), [](detail::node const& n0, detail::node const& n1) + {return n0.offset != n1.offset ? n0.offset < n1.offset : n0.start < n1.start;}); + std::cerr << "shape_index_featureset: Query size=" << offsets_.size() << std::endl; MAPNIK_LOG_DEBUG(shape) << "shape_index_featureset: Query size=" << offsets_.size(); itr_ = offsets_.begin(); } @@ -83,7 +85,15 @@ feature_ptr shape_index_featureset::next() while ( itr_ != offsets_.end()) { - shape_ptr_->move_to(*itr_++); + int offset = itr_->offset; + shape_ptr_->move_to(offset); + std::vector> parts; + while (itr_->offset == offset && itr_ != offsets_.end()) + { + if (itr_->start!= -1) parts.emplace_back(itr_->start, itr_->end); + ++itr_; + } + //std::cerr << "PARTS SIZE=" << parts.size() <<" offset=" << offset << std::endl; mapnik::value_integer feature_id = shape_ptr_->id(); shape_file::record_type record(shape_ptr_->reclength_ * 2); shape_ptr_->shp().read_record(record); @@ -124,7 +134,8 @@ feature_ptr shape_index_featureset::next() { shape_io::read_bbox(record, feature_bbox_); if (!filter_.pass(feature_bbox_)) continue; - feature->set_geometry(shape_io::read_polyline(record)); + if (parts.size() < 2) feature->set_geometry(shape_io::read_polyline(record)); + else feature->set_geometry(shape_io::read_polyline_parts(record, parts)); break; } case shape_io::shape_polygon: @@ -133,7 +144,8 @@ feature_ptr shape_index_featureset::next() { shape_io::read_bbox(record, feature_bbox_); if (!filter_.pass(feature_bbox_)) continue; - feature->set_geometry(shape_io::read_polygon(record)); + if (parts.size() < 2) feature->set_geometry(shape_io::read_polygon(record)); + else feature->set_geometry(shape_io::read_polygon_parts(record, parts)); break; } default : diff --git a/plugins/input/shape/shape_index_featureset.hpp b/plugins/input/shape/shape_index_featureset.hpp index 80c8fa681..3ea8a8e45 100644 --- a/plugins/input/shape/shape_index_featureset.hpp +++ b/plugins/input/shape/shape_index_featureset.hpp @@ -45,6 +45,16 @@ using mapnik::box2d; using mapnik::feature_ptr; using mapnik::context_ptr; +namespace detail +{ +struct node +{ + int offset; + int start; + int end; +}; +} + template class shape_index_featureset : public Featureset { @@ -63,8 +73,8 @@ private: context_ptr ctx_; std::unique_ptr shape_ptr_; const std::unique_ptr tr_; - std::vector offsets_; - std::vector::iterator itr_; + std::vector offsets_; + std::vector::iterator itr_; std::vector attr_ids_; mapnik::value_integer row_limit_; mutable int count_; diff --git a/plugins/input/shape/shape_io.cpp b/plugins/input/shape/shape_io.cpp index bb9d78334..5dd591996 100644 --- a/plugins/input/shape/shape_io.cpp +++ b/plugins/input/shape/shape_io.cpp @@ -125,6 +125,7 @@ mapnik::geometry::geometry shape_io::read_polyline(shape_file::record_ty std::for_each(parts.begin(), parts.end(), [&](int & part) { part = record.read_ndr_integer();}); int start, end; mapnik::geometry::multi_line_string multi_line; + multi_line.reserve(num_parts); for (int k = 0; k < num_parts; ++k) { start = parts[k]; @@ -152,6 +153,34 @@ mapnik::geometry::geometry shape_io::read_polyline(shape_file::record_ty return geom; } +mapnik::geometry::geometry shape_io::read_polyline_parts(shape_file::record_type & record, std::vector> const& parts) +{ + mapnik::geometry::geometry geom; // default empty + int total_num_parts = record.read_ndr_integer(); + int num_parts = parts.size(); + mapnik::geometry::multi_line_string multi_line; + multi_line.reserve(num_parts); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k].first; + int end = parts[k].second; + unsigned pos = 4 + 32 + 8 + 4 * total_num_parts + start * 16; + record.set_pos(pos); + + mapnik::geometry::line_string line; + line.reserve(end - start); + for (int j = start; j < end; ++j) + { + double x = record.read_double(); + double y = record.read_double(); + line.emplace_back(x, y); + } + multi_line.push_back(std::move(line)); + } + geom = std::move(multi_line); + return geom; +} + mapnik::geometry::geometry shape_io::read_polygon(shape_file::record_type & record) { @@ -207,3 +236,53 @@ mapnik::geometry::geometry shape_io::read_polygon(shape_file::record_typ mapnik::geometry::correct(geom); return geom; } + +mapnik::geometry::geometry shape_io::read_polygon_parts(shape_file::record_type & record, std::vector> const& parts) +{ + mapnik::geometry::geometry geom; // default empty + int total_num_parts = record.read_ndr_integer(); + mapnik::geometry::polygon poly; + mapnik::geometry::multi_polygon multi_poly; + int num_parts = parts.size(); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k].first; + int end = parts[k].second; + unsigned pos = 4 + 32 + 8 + 4 * total_num_parts + start * 16; + record.set_pos(pos); + mapnik::geometry::linear_ring ring; + ring.reserve(end - start); + for (int j = start; j < end; ++j) + { + double x = record.read_double(); + double y = record.read_double(); + ring.emplace_back(x, y); + } + if (k == 0) + { + poly.set_exterior_ring(std::move(ring)); + } + else if (mapnik::util::is_clockwise(ring)) + { + multi_poly.emplace_back(std::move(poly)); + poly.interior_rings.clear(); + poly.set_exterior_ring(std::move(ring)); + } + else + { + poly.add_hole(std::move(ring)); + } + } + + if (multi_poly.size() > 0) // multi + { + multi_poly.emplace_back(std::move(poly)); + geom = std::move(multi_poly); + } + else + { + geom = std::move(poly); + } + mapnik::geometry::correct(geom); + return geom; +} diff --git a/plugins/input/shape/shape_io.hpp b/plugins/input/shape/shape_io.hpp index ab28f9999..c2fd3a564 100644 --- a/plugins/input/shape/shape_io.hpp +++ b/plugins/input/shape/shape_io.hpp @@ -80,6 +80,8 @@ public: static void read_bbox(shape_file::record_type & record, mapnik::box2d & bbox); static mapnik::geometry::geometry read_polyline(shape_file::record_type & record); static mapnik::geometry::geometry read_polygon(shape_file::record_type & record); + static mapnik::geometry::geometry read_polyline_parts(shape_file::record_type & record,std::vector> const& parts); + static mapnik::geometry::geometry read_polygon_parts(shape_file::record_type & record, std::vector> const& parts); shapeType type_; shape_file shp_; diff --git a/plugins/input/shape/shapefile.hpp b/plugins/input/shape/shapefile.hpp index 664dc8852..15e5c7757 100644 --- a/plugins/input/shape/shapefile.hpp +++ b/plugins/input/shape/shapefile.hpp @@ -105,6 +105,11 @@ struct shape_record pos += n; } + void set_pos(unsigned pos_) + { + pos = pos_; + } + int read_ndr_integer() { std::int32_t val; diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index c57372140..5dea5ec3c 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "shapefile.hpp" #include "shape_io.hpp" @@ -38,12 +39,27 @@ const int DEFAULT_DEPTH = 8; const double DEFAULT_RATIO=0.55; +namespace +{ +struct node +{ + node(int offset_, int start_, int end_) + : offset(offset_), + start(start_), + end(end_) {} + int offset; + int start; + int end; +}; +} + int main (int argc,char** argv) { using namespace mapnik; namespace po = boost::program_options; bool verbose=false; + bool index_parts = false; unsigned int depth=DEFAULT_DEPTH; double ratio=DEFAULT_RATIO; std::vector shape_files; @@ -54,6 +70,7 @@ int main (int argc,char** argv) desc.add_options() ("help,h", "produce usage message") ("version,V","print version string") + ("index-parts","index individual shape parts") ("verbose,v","verbose output") ("depth,d", po::value(), "max tree depth\n(default 8)") ("ratio,r",po::value(),"split ratio (default 0.55)") @@ -81,6 +98,10 @@ int main (int argc,char** argv) { verbose = true; } + if (vm.count("index-parts")) + { + index_parts = true; + } if (vm.count("depth")) { depth = vm["depth"].as(); @@ -159,7 +180,7 @@ int main (int argc,char** argv) int pos = 50; shx.seek(pos * 2); - mapnik::quad_tree tree(extent, depth, ratio); + mapnik::quad_tree tree(extent, depth, ratio); int count = 0; if (shape_type != shape_io::shape_null) @@ -188,17 +209,56 @@ int main (int argc,char** argv) double y=shp.read_double(); item_ext=box2d(x,y,x,y); } + else if (index_parts && + (shape_type == shape_io::shape_polygon || shape_type == shape_io::shape_polygonm || shape_type == shape_io::shape_polygonz + || shape_type == shape_io::shape_polyline || shape_type == shape_io::shape_polylinem || shape_type == shape_io::shape_polylinez)) + { + shp.read_envelope(item_ext); + int num_parts = shp.read_ndr_integer(); + int num_points = shp.read_ndr_integer(); + std::vector parts; + parts.resize(num_parts); + std::for_each(parts.begin(), parts.end(), [&](int & part) { part = shp.read_ndr_integer();}); + for (int k = 0; k < num_parts; ++k) + { + int start = parts[k]; + int end; + if (k == num_parts - 1) end = num_points; + else end = parts[k + 1]; + + mapnik::geometry::linear_ring ring; + ring.reserve(end - start); + for (int j = start; j < end; ++j) + { + double x = shp.read_double(); + double y = shp.read_double(); + ring.emplace_back(x, y); + } + item_ext = mapnik::geometry::envelope(ring); + if (item_ext.valid()) + { + if (verbose) + { + std::clog << "record number " << record_number << " box=" << item_ext << std::endl; + } + tree.insert(node(offset * 2, start, end),item_ext); + ++count; + } + } + item_ext = mapnik::box2d(); //invalid + } else { shp.read_envelope(item_ext); } - if (verbose) - { - std::clog << "record number " << record_number << " box=" << item_ext << std::endl; - } + if (item_ext.valid()) { - tree.insert(offset * 2,item_ext); + if (verbose) + { + std::clog << "record number " << record_number << " box=" << item_ext << std::endl; + } + tree.insert(node(offset * 2,-1,0),item_ext); ++count; } } From 88a04a120f015767c4cd2dd52c638619c35a3340 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 11:56:01 +0000 Subject: [PATCH 15/37] remove stderr --- plugins/input/shape/shape_index_featureset.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp index 0fe625487..9fa271ae2 100644 --- a/plugins/input/shape/shape_index_featureset.cpp +++ b/plugins/input/shape/shape_index_featureset.cpp @@ -70,7 +70,6 @@ shape_index_featureset::shape_index_featureset(filterT const& filter, } std::sort(offsets_.begin(), offsets_.end(), [](detail::node const& n0, detail::node const& n1) {return n0.offset != n1.offset ? n0.offset < n1.offset : n0.start < n1.start;}); - std::cerr << "shape_index_featureset: Query size=" << offsets_.size() << std::endl; MAPNIK_LOG_DEBUG(shape) << "shape_index_featureset: Query size=" << offsets_.size(); itr_ = offsets_.begin(); } From 4c6632cf9386094a8098884944497234a72765e3 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 13:19:16 +0000 Subject: [PATCH 16/37] shapeindex : remove duplicate node defs + add default ctor --- .../input/shape/shape_index_featureset.cpp | 6 ++--- .../input/shape/shape_index_featureset.hpp | 13 +++++++---- utils/shapeindex/shapeindex.cpp | 22 ++++--------------- 3 files changed, 16 insertions(+), 25 deletions(-) diff --git a/plugins/input/shape/shape_index_featureset.cpp b/plugins/input/shape/shape_index_featureset.cpp index 9fa271ae2..bb9da6ecb 100644 --- a/plugins/input/shape/shape_index_featureset.cpp +++ b/plugins/input/shape/shape_index_featureset.cpp @@ -63,12 +63,12 @@ shape_index_featureset::shape_index_featureset(filterT const& filter, if (index) { #if defined(MAPNIK_MEMORY_MAPPED_FILE) - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #else - mapnik::util::spatial_index::query(filter, index->file(), offsets_); + mapnik::util::spatial_index::query(filter, index->file(), offsets_); #endif } - std::sort(offsets_.begin(), offsets_.end(), [](detail::node const& n0, detail::node const& n1) + std::sort(offsets_.begin(), offsets_.end(), [](mapnik::detail::node const& n0, mapnik::detail::node const& n1) {return n0.offset != n1.offset ? n0.offset < n1.offset : n0.start < n1.start;}); MAPNIK_LOG_DEBUG(shape) << "shape_index_featureset: Query size=" << offsets_.size(); itr_ = offsets_.begin(); diff --git a/plugins/input/shape/shape_index_featureset.hpp b/plugins/input/shape/shape_index_featureset.hpp index 3ea8a8e45..d104e0f20 100644 --- a/plugins/input/shape/shape_index_featureset.hpp +++ b/plugins/input/shape/shape_index_featureset.hpp @@ -45,15 +45,20 @@ using mapnik::box2d; using mapnik::feature_ptr; using mapnik::context_ptr; -namespace detail +namespace mapnik { namespace detail { struct node { + node() = default; + node(int offset_, int start_, int end_) + : offset(offset_), + start(start_), + end(end_) {} int offset; int start; int end; }; -} +}} // ns template class shape_index_featureset : public Featureset @@ -73,8 +78,8 @@ private: context_ptr ctx_; std::unique_ptr shape_ptr_; const std::unique_ptr tr_; - std::vector offsets_; - std::vector::iterator itr_; + std::vector offsets_; + std::vector::iterator itr_; std::vector attr_ids_; mapnik::value_integer row_limit_; mutable int count_; diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index 5dea5ec3c..ccab95913 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -29,7 +29,7 @@ #include #include "shapefile.hpp" #include "shape_io.hpp" - +#include "shape_index_featureset.hpp" #pragma GCC diagnostic push #include #include @@ -39,20 +39,6 @@ const int DEFAULT_DEPTH = 8; const double DEFAULT_RATIO=0.55; -namespace -{ -struct node -{ - node(int offset_, int start_, int end_) - : offset(offset_), - start(start_), - end(end_) {} - int offset; - int start; - int end; -}; -} - int main (int argc,char** argv) { using namespace mapnik; @@ -180,7 +166,7 @@ int main (int argc,char** argv) int pos = 50; shx.seek(pos * 2); - mapnik::quad_tree tree(extent, depth, ratio); + mapnik::quad_tree tree(extent, depth, ratio); int count = 0; if (shape_type != shape_io::shape_null) @@ -241,7 +227,7 @@ int main (int argc,char** argv) { std::clog << "record number " << record_number << " box=" << item_ext << std::endl; } - tree.insert(node(offset * 2, start, end),item_ext); + tree.insert(mapnik::detail::node(offset * 2, start, end),item_ext); ++count; } } @@ -258,7 +244,7 @@ int main (int argc,char** argv) { std::clog << "record number " << record_number << " box=" << item_ext << std::endl; } - tree.insert(node(offset * 2,-1,0),item_ext); + tree.insert(mapnik::detail::node(offset * 2,-1,0),item_ext); ++count; } } From 412fa20eb8bf454f1a082d2fd7273a9a0e3041e4 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 13:23:50 +0000 Subject: [PATCH 17/37] shapeindex: indicate default behaviour in -h(--help) --- utils/shapeindex/shapeindex.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/utils/shapeindex/shapeindex.cpp b/utils/shapeindex/shapeindex.cpp index ccab95913..eddb28d84 100644 --- a/utils/shapeindex/shapeindex.cpp +++ b/utils/shapeindex/shapeindex.cpp @@ -46,8 +46,8 @@ int main (int argc,char** argv) bool verbose=false; bool index_parts = false; - unsigned int depth=DEFAULT_DEPTH; - double ratio=DEFAULT_RATIO; + unsigned int depth = DEFAULT_DEPTH; + double ratio = DEFAULT_RATIO; std::vector shape_files; try @@ -56,7 +56,7 @@ int main (int argc,char** argv) desc.add_options() ("help,h", "produce usage message") ("version,V","print version string") - ("index-parts","index individual shape parts") + ("index-parts","index individual shape parts (default: no)") ("verbose,v","verbose output") ("depth,d", po::value(), "max tree depth\n(default 8)") ("ratio,r",po::value(),"split ratio (default 0.55)") From 102671e49869c1982165e3b6279af959d9e77302 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 14:22:09 +0000 Subject: [PATCH 18/37] add test with `--index-parts` option --- test/unit/datasource/shapeindex.cpp | 55 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/test/unit/datasource/shapeindex.cpp b/test/unit/datasource/shapeindex.cpp index e16967812..3be5c9b2d 100644 --- a/test/unit/datasource/shapeindex.cpp +++ b/test/unit/datasource/shapeindex.cpp @@ -58,14 +58,18 @@ std::size_t count_shapefile_features(std::string const& filename) return feature_count; } -int create_shapefile_index(std::string const& filename, bool silent = true) +int create_shapefile_index(std::string const& filename, bool index_parts, bool silent = true) { std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; } - cmd += "shapeindex " + filename; + + cmd += "shapeindex"; + if (index_parts) cmd+= " --index-parts "; + cmd += filename; + std::cerr << cmd << std::endl; if (silent) { #ifndef _WINDOWS @@ -90,28 +94,31 @@ TEST_CASE("shapeindex") { if (boost::iends_with(path,".shp")) { - std::string index_path = path.substr(0, path.rfind(".")) + ".index"; - // remove *.index if present - if (mapnik::util::exists(index_path)) + for (bool index_parts : {false, true} ) { - mapnik::util::remove(index_path); - } - // count features - std::size_t feature_count = count_shapefile_features(path); - // create *.index - create_shapefile_index(path); - if (feature_count == 0) - { - REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features - } - // count features - std::size_t feature_count_indexed = count_shapefile_features(path); - // ensure number of features are the same - REQUIRE(feature_count == feature_count_indexed); - // remove *.index if present - if (mapnik::util::exists(index_path)) - { - mapnik::util::remove(index_path); + std::string index_path = path.substr(0, path.rfind(".")) + ".index"; + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } + // count features + std::size_t feature_count = count_shapefile_features(path); + // create *.index + create_shapefile_index(path, index_parts); + if (feature_count == 0) + { + REQUIRE(!mapnik::util::exists(index_path)); // index won't be created if there's no features + } + // count features + std::size_t feature_count_indexed = count_shapefile_features(path); + // ensure number of features are the same + REQUIRE(feature_count == feature_count_indexed); + // remove *.index if present + if (mapnik::util::exists(index_path)) + { + mapnik::util::remove(index_path); + } } } } From b513d6a07b52fc2666d101248428d5e5a2919ab2 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 14:24:25 +0000 Subject: [PATCH 19/37] don't export DYLD_LIBRARY_PATH multiple times --- test/unit/datasource/csv.cpp | 2 +- test/unit/datasource/geojson.cpp | 2 +- test/unit/datasource/postgis.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/datasource/csv.cpp b/test/unit/datasource/csv.cpp index 72e87193c..7db9bd1f1 100644 --- a/test/unit/datasource/csv.cpp +++ b/test/unit/datasource/csv.cpp @@ -80,7 +80,7 @@ int create_disk_index(std::string const& filename, bool silent = true) std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; } cmd += "mapnik-index " + filename; if (silent) diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp index d27347c6b..7b8c1038c 100644 --- a/test/unit/datasource/geojson.cpp +++ b/test/unit/datasource/geojson.cpp @@ -66,7 +66,7 @@ int create_disk_index(std::string const& filename, bool silent = true) std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; } cmd += "mapnik-index " + filename; if (silent) diff --git a/test/unit/datasource/postgis.cpp b/test/unit/datasource/postgis.cpp index 4aaa76fe1..f814dd2f4 100644 --- a/test/unit/datasource/postgis.cpp +++ b/test/unit/datasource/postgis.cpp @@ -43,7 +43,7 @@ int run(std::string const& command, bool silent = false) std::string cmd; if (std::getenv("DYLD_LIBRARY_PATH") != nullptr) { - cmd += std::string("export DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " && "; + cmd += std::string("DYLD_LIBRARY_PATH=") + std::getenv("DYLD_LIBRARY_PATH") + " "; } cmd += command; if (silent) @@ -91,4 +91,4 @@ TEST_CASE("postgis") { } -} \ No newline at end of file +} From 869bff43f0e82bd7ebd6c93679d61f310f4ebe98 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 4 Jan 2016 15:15:05 +0000 Subject: [PATCH 20/37] remove debug printing --- test/unit/datasource/shapeindex.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/datasource/shapeindex.cpp b/test/unit/datasource/shapeindex.cpp index 3be5c9b2d..79ac9a9e6 100644 --- a/test/unit/datasource/shapeindex.cpp +++ b/test/unit/datasource/shapeindex.cpp @@ -69,7 +69,6 @@ int create_shapefile_index(std::string const& filename, bool index_parts, bool s cmd += "shapeindex"; if (index_parts) cmd+= " --index-parts "; cmd += filename; - std::cerr << cmd << std::endl; if (silent) { #ifndef _WINDOWS From ee0395df7a95365b0608ef7d815abd54aff6fe4d Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 5 Jan 2016 10:20:21 +0000 Subject: [PATCH 21/37] add basic read/write header support (quad_tree + spatial_index) ref (#3216) --- include/mapnik/quad_tree.hpp | 7 +------ include/mapnik/util/spatial_index.hpp | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/include/mapnik/quad_tree.hpp b/include/mapnik/quad_tree.hpp index 092bf4d60..d60ee5d32 100644 --- a/include/mapnik/quad_tree.hpp +++ b/include/mapnik/quad_tree.hpp @@ -179,12 +179,7 @@ public: "Values stored in quad-tree must be standard layout types to allow serialisation"); char header[16]; std::memset(header,0,16); - header[0]='m'; - header[1]='a'; - header[2]='p'; - header[3]='n'; - header[4]='i'; - header[5]='k'; + std::strcpy(header,"mapnik-index"); out.write(header,16); write_node(out,root_); } diff --git a/include/mapnik/util/spatial_index.hpp b/include/mapnik/util/spatial_index.hpp index 021bed59c..da30f058e 100644 --- a/include/mapnik/util/spatial_index.hpp +++ b/include/mapnik/util/spatial_index.hpp @@ -30,6 +30,7 @@ #include // stl #include +#include using mapnik::box2d; using mapnik::query; @@ -44,7 +45,6 @@ public: static box2d bounding_box( InputStream& in ); static void query_first_n(Filter const& filter, InputStream & in, std::vector& pos, std::size_t count); private: - spatial_index(); ~spatial_index(); spatial_index(spatial_index const&); @@ -53,12 +53,23 @@ private: static void read_envelope(InputStream& in, box2d& envelope); static void query_node(Filter const& filter, InputStream& in, std::vector & results); static void query_first_n_impl(Filter const& filter, InputStream& in, std::vector & results, std::size_t count); + static bool check_header(InputStream& in); }; +template +bool spatial_index::check_header(InputStream& in) +{ + static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout type"); + char header[17]; // mapnik-index + std::memset(header, 0, 17); + in.read(header,16); + return (std::strncmp(header, "mapnik-index",12) == 0); +} + template box2d spatial_index::bounding_box(InputStream& in) { - static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout type"); + if (!check_header(in)) throw std::runtime_error("Invalid index file"); in.seekg(16 + 4, std::ios::beg); box2d box; read_envelope(in, box); @@ -69,7 +80,7 @@ box2d spatial_index::bounding_box(InputStrea template void spatial_index::query(Filter const& filter, InputStream& in, std::vector& results) { - static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout types"); + if (!check_header(in)) throw std::runtime_error("Invalid index file"); in.seekg(16, std::ios::beg); query_node(filter, in, results); } @@ -104,7 +115,7 @@ void spatial_index::query_node(Filter const& filter, template void spatial_index::query_first_n(Filter const& filter, InputStream& in, std::vector& results, std::size_t count) { - static_assert(std::is_standard_layout::value, "Values stored in quad-tree must be standard layout types"); + if (!check_header(in)) throw std::runtime_error("Invalid index file"); in.seekg(16, std::ios::beg); query_first_n_impl(filter, in, results, count); } From a86df6349013a4325467584d6dcd1dac3f24f1d1 Mon Sep 17 00:00:00 2001 From: bergwerkgis Date: Tue, 5 Jan 2016 14:15:13 +0100 Subject: [PATCH 22/37] [skip ci] Windows: remove check for unix style "find" --- scripts/build-appveyor.bat | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/scripts/build-appveyor.bat b/scripts/build-appveyor.bat index 1f332d53b..11981c5c3 100644 --- a/scripts/build-appveyor.bat +++ b/scripts/build-appveyor.bat @@ -28,27 +28,6 @@ ECHO ======== SET PATH=C:\Python27;%PATH% SET PATH=C:\Program Files\7-Zip;%PATH% -:: *nix style find command comes with git: -ECHO checking for unix style 'find' -find %USERPROFILE% -name "*.blabla" -IF %ERRORLEVEL% EQU 0 GOTO NIX_FIND_FOUND - -IF DEFINED GIT_INSTALL_ROOT SET TEMP_GIT_DIR=%GIT_INSTALL_ROOT%&& GOTO TEST_FIND_AGAIN -IF EXIST "C:\Program Files (x86)\Git" SET TEMP_GIT_DIR=C:\Program Files (x86)\Git&& GOTO TEST_FIND_AGAIN -IF EXIST "C:\Program Files\Git" SET TEMP_GIT_DIR=C:\Program Files\Git&& GOTO TEST_FIND_AGAIN - -:TEST_FIND_AGAIN -SET PATH=%TEMP_GIT_DIR%\bin;%PATH% -SET PATH=%TEMP_GIT_DIR%\usr\bin;%PATH% -ECHO %PATH% -::check again -find %USERPROFILE% -name "*.blabla" -IF %ERRORLEVEL% NEQ 0 (ECHO unix style find not found && GOTO ERROR) - - -:NIX_FIND_FOUND -ECHO find was found - ::cloning mapnik-gyp if EXIST mapnik-gyp ECHO mapnik-gyp already cloned && GOTO MAPNIK_GYP_ALREADY_HERE CALL git clone https://github.com/mapnik/mapnik-gyp.git From 5cd3645cd1c01cc66b51f3378c5e52af523d38a0 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 5 Jan 2016 16:58:37 +0000 Subject: [PATCH 23/37] keep address-sanitizer happy ref (https://github.com/mapbox/mapnik-vector-tile/pull/171) --- include/mapnik/json/positions_grammar.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mapnik/json/positions_grammar.hpp b/include/mapnik/json/positions_grammar.hpp index a652e8f59..045b8cf8e 100644 --- a/include/mapnik/json/positions_grammar.hpp +++ b/include/mapnik/json/positions_grammar.hpp @@ -63,10 +63,10 @@ struct set_position_impl struct push_position_impl { using result_type = void; - template + template result_type operator() (T0 & coords, T1 const& pos) const { - if (pos) coords.push_back(*pos); + if (pos) coords.empace_back(*pos); } }; From 7b2da35c0118c978aa029d16b901002306c08e23 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 5 Jan 2016 19:52:36 +0000 Subject: [PATCH 24/37] fix typo doh --- include/mapnik/json/positions_grammar.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/json/positions_grammar.hpp b/include/mapnik/json/positions_grammar.hpp index 045b8cf8e..153542257 100644 --- a/include/mapnik/json/positions_grammar.hpp +++ b/include/mapnik/json/positions_grammar.hpp @@ -66,7 +66,7 @@ struct push_position_impl template result_type operator() (T0 & coords, T1 const& pos) const { - if (pos) coords.empace_back(*pos); + if (pos) coords.emplace_back(*pos); } }; From c82b4c8ba3cc425ca0fe76ab6bf0bd01df6dabed Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 5 Jan 2016 13:34:11 -0800 Subject: [PATCH 25/37] fix mason-latest publishing, broken since e547ee12 --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 656ac257a..0dcfac089 100644 --- a/.travis.yml +++ b/.travis.yml @@ -83,7 +83,7 @@ script: - if [[ ${COVERAGE} != true ]]; then make bench; fi - - if [[ ${TEST_RESULT} != 0 ]]; then exit $TEST_RESULT ; fi; + - if [[ ${TEST_RESULT:-0} != 0 ]]; then exit $TEST_RESULT ; fi; - if [[ ${MASON_PUBLISH} == true ]]; then ./mason_latest.sh build; ./mason_latest.sh link; From 96dff395a4f6cea57a7e4878c48e0993ff92f6e5 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 5 Jan 2016 15:18:02 -0800 Subject: [PATCH 26/37] fix usage of base in csv unit tests --- test/unit/datasource/csv.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/unit/datasource/csv.cpp b/test/unit/datasource/csv.cpp index 7db9bd1f1..cabf47499 100644 --- a/test/unit/datasource/csv.cpp +++ b/test/unit/datasource/csv.cpp @@ -68,6 +68,10 @@ mapnik::datasource_ptr get_csv_ds(std::string const& file_name, bool strict = tr mapnik::parameters params; params["type"] = std::string("csv"); params["file"] = file_name; + if (!base.empty()) + { + params["base"] = base; + } params["strict"] = mapnik::value_bool(strict); auto ds = mapnik::datasource_cache::instance().create(params); // require a non-null pointer returned @@ -288,7 +292,7 @@ TEST_CASE("csv") { INFO(ret_posix); CHECK(mapnik::util::exists(filepath + ".index")); } - auto ds = get_csv_ds(filepath,true,base); + auto ds = get_csv_ds(filename,true,base); CHECK(ds->type() == mapnik::datasource::datasource_t::Vector); auto fields = ds->get_descriptor().get_descriptors(); require_field_names(fields, {"Precinct", "Phone", "Address", "City", "geo_longitude", "geo_latitude", "geo_accuracy"}); From ca3b0c43e78b7445ed9cd6c8ddeb619ced1410dc Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 5 Jan 2016 16:42:36 -0800 Subject: [PATCH 27/37] upgrade catch.hpp --- test/catch.hpp | 2966 ++++++++++++++++++++++++++++++------------------ 1 file changed, 1871 insertions(+), 1095 deletions(-) diff --git a/test/catch.hpp b/test/catch.hpp index 5b616a2b6..3b759681e 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -1,6 +1,6 @@ /* - * CATCH v1.1 build 1 (master branch) - * Generated: 2015-03-27 18:00:16.346230 + * Catch v1.3.2 + * Generated: 2015-12-28 15:07:07.166291 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly * Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved. @@ -13,9 +13,13 @@ #define TWOBLUECUBES_CATCH_HPP_INCLUDED -// #included from: internal/catch_suppress_warnings.h +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif -#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED +// #included from: internal/catch_suppress_warnings.h #ifdef __clang__ # ifdef __ICC // icpc defines the __clang__ macro @@ -30,6 +34,8 @@ # pragma clang diagnostic ignored "-Wpadded" # pragma clang diagnostic ignored "-Wc++98-compat" # pragma clang diagnostic ignored "-Wc++98-compat-pedantic" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" # endif #elif defined __GNUC__ # pragma GCC diagnostic ignored "-Wvariadic-macros" @@ -37,7 +43,6 @@ # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wpadded" #endif - #if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) # define CATCH_IMPL #endif @@ -69,16 +74,42 @@ // #included from: catch_compiler_capabilities.h #define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED -// Much of the following code is based on Boost (1.53) +// Detect a number of compiler features - mostly C++11/14 conformance - by compiler +// The following features are defined: +// +// CATCH_CONFIG_CPP11_NULLPTR : is nullptr supported? +// CATCH_CONFIG_CPP11_NOEXCEPT : is noexcept supported? +// CATCH_CONFIG_CPP11_GENERATED_METHODS : The delete and default keywords for compiler generated methods +// CATCH_CONFIG_CPP11_IS_ENUM : std::is_enum is supported? +// CATCH_CONFIG_CPP11_TUPLE : std::tuple is supported +// CATCH_CONFIG_CPP11_LONG_LONG : is long long supported? +// CATCH_CONFIG_CPP11_OVERRIDE : is override supported? +// CATCH_CONFIG_CPP11_UNIQUE_PTR : is unique_ptr supported (otherwise use auto_ptr) + +// CATCH_CONFIG_CPP11_OR_GREATER : Is C++11 supported? + +// CATCH_CONFIG_VARIADIC_MACROS : are variadic macros supported? + +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_CPP11_NO_NULLPTR) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +// All the C++11 features can be disabled with CATCH_CONFIG_NO_CPP11 #ifdef __clang__ # if __has_feature(cxx_nullptr) -# define CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR # endif # if __has_feature(cxx_noexcept) -# define CATCH_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT # endif #endif // __clang__ @@ -87,52 +118,30 @@ // Borland #ifdef __BORLANDC__ -#if (__BORLANDC__ > 0x582 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __BORLANDC__ //////////////////////////////////////////////////////////////////////////////// // EDG #ifdef __EDG_VERSION__ -#if (__EDG_VERSION__ > 238 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __EDG_VERSION__ //////////////////////////////////////////////////////////////////////////////// // Digital Mars #ifdef __DMC__ -#if (__DMC__ > 0x840 ) -//#define CATCH_CONFIG_SFINAE // Not confirmed -#endif - #endif // __DMC__ //////////////////////////////////////////////////////////////////////////////// // GCC #ifdef __GNUC__ -#if __GNUC__ < 3 - -#if (__GNUC_MINOR__ >= 96 ) -//#define CATCH_CONFIG_SFINAE +#if __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR #endif -#elif __GNUC__ >= 3 - -// #define CATCH_CONFIG_SFINAE // Taking this out completely for now - -#endif // __GNUC__ < 3 - -#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) ) - -#define CATCH_CONFIG_CPP11_NULLPTR -#endif +// - otherwise more recent versions define __cplusplus >= 201103L +// and will get picked up below #endif // __GNUC__ @@ -141,36 +150,101 @@ #ifdef _MSC_VER #if (_MSC_VER >= 1600) -#define CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR #endif -#if (_MSC_VER >= 1310 ) // (VC++ 7.0+) -//#define CATCH_CONFIG_SFINAE // Not confirmed +#if (_MSC_VER >= 1900 ) // (VC++ 13 (VS2015)) +#define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +#define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS #endif #endif // _MSC_VER +//////////////////////////////////////////////////////////////////////////////// + // Use variadic macros if the compiler supports them #if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \ ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \ ( defined __GNUC__ && __GNUC__ >= 3 ) || \ ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L ) -#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS -#define CATCH_CONFIG_VARIADIC_MACROS -#endif +#define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS #endif //////////////////////////////////////////////////////////////////////////////// // C++ language feature support -// detect language version: -#if (__cplusplus == 201103L) -# define CATCH_CPP11 -# define CATCH_CPP11_OR_GREATER -#elif (__cplusplus >= 201103L) +// catch all support for C++11 +#if defined(__cplusplus) && __cplusplus >= 201103L + # define CATCH_CPP11_OR_GREATER + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) +# define CATCH_INTERNAL_CONFIG_CPP11_NULLPTR +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# define CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# define CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# define CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM +# endif + +# ifndef CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# define CATCH_INTERNAL_CONFIG_CPP11_TUPLE +# endif + +# ifndef CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# define CATCH_INTERNAL_CONFIG_VARIADIC_MACROS +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) +# define CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG +# endif + +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) +# define CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE +# endif +# if !defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) +# define CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR +# endif + +#endif // __cplusplus >= 201103L + +// Now set the actual defines based on the above + anything the user has configured +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NO_NULLPTR) && !defined(CATCH_CONFIG_CPP11_NULLPTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NULLPTR +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NO_NOEXCEPT) && !defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_NOEXCEPT +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_NO_GENERATED_METHODS) && !defined(CATCH_CONFIG_CPP11_GENERATED_METHODS) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_GENERATED_METHODS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_NO_IS_ENUM) && !defined(CATCH_CONFIG_CPP11_IS_ENUM) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_IS_ENUM +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_CPP11_NO_TUPLE) && !defined(CATCH_CONFIG_CPP11_TUPLE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_TUPLE +#endif +#if defined(CATCH_INTERNAL_CONFIG_VARIADIC_MACROS) && !defined(CATCH_CONFIG_NO_VARIADIC_MACROS) && !defined(CATCH_CONFIG_VARIADIC_MACROS) +# define CATCH_CONFIG_VARIADIC_MACROS +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_LONG_LONG) && !defined(CATCH_CONFIG_CPP11_LONG_LONG) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_LONG_LONG +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_OVERRIDE) && !defined(CATCH_CONFIG_CPP11_OVERRIDE) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_OVERRIDE +#endif +#if defined(CATCH_INTERNAL_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_UNIQUE_PTR) && !defined(CATCH_CONFIG_CPP11_UNIQUE_PTR) && !defined(CATCH_CONFIG_NO_CPP11) +# define CATCH_CONFIG_CPP11_UNIQUE_PTR #endif // noexcept support: @@ -182,10 +256,38 @@ # define CATCH_NOEXCEPT_IS(x) #endif +// nullptr support +#ifdef CATCH_CONFIG_CPP11_NULLPTR +# define CATCH_NULL nullptr +#else +# define CATCH_NULL NULL +#endif + +// override support +#ifdef CATCH_CONFIG_CPP11_OVERRIDE +# define CATCH_OVERRIDE override +#else +# define CATCH_OVERRIDE +#endif + +// unique_ptr support +#ifdef CATCH_CONFIG_CPP11_UNIQUE_PTR +# define CATCH_AUTO_PTR( T ) std::unique_ptr +#else +# define CATCH_AUTO_PTR( T ) std::auto_ptr +#endif + namespace Catch { + struct IConfig; + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + class NonCopyable { -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS NonCopyable( NonCopyable const& ) = delete; NonCopyable( NonCopyable && ) = delete; NonCopyable& operator = ( NonCopyable const& ) = delete; @@ -248,7 +350,7 @@ namespace Catch { SourceLineInfo(); SourceLineInfo( char const* _file, std::size_t _line ); SourceLineInfo( SourceLineInfo const& other ); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SourceLineInfo( SourceLineInfo && ) = default; SourceLineInfo& operator = ( SourceLineInfo const& ) = default; SourceLineInfo& operator = ( SourceLineInfo && ) = default; @@ -270,6 +372,9 @@ namespace Catch { void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ); + void seedRng( IConfig const& config ); + unsigned int rngSeed(); + // Use this in variadic streaming macros to allow // >> +StreamEndStop // as well as @@ -355,7 +460,7 @@ namespace Catch { template class Ptr { public: - Ptr() : m_p( NULL ){} + Ptr() : m_p( CATCH_NULL ){} Ptr( T* p ) : m_p( p ){ if( m_p ) m_p->addRef(); @@ -371,7 +476,7 @@ namespace Catch { void reset() { if( m_p ) m_p->release(); - m_p = NULL; + m_p = CATCH_NULL; } Ptr& operator = ( T* p ){ Ptr temp( p ); @@ -384,12 +489,11 @@ namespace Catch { return *this; } void swap( Ptr& other ) { std::swap( m_p, other.m_p ); } - T* get() { return m_p; } - const T* get() const{ return m_p; } + T* get() const{ return m_p; } T& operator*() const { return *m_p; } T* operator->() const { return m_p; } - bool operator !() const { return m_p == NULL; } - operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); } + bool operator !() const { return m_p == CATCH_NULL; } + operator SafeBool::type() const { return SafeBool::makeSafe( m_p != CATCH_NULL ); } private: T* m_p; @@ -486,9 +590,13 @@ namespace Catch { struct ITestCaseRegistry { virtual ~ITestCaseRegistry(); virtual std::vector const& getAllTests() const = 0; - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const = 0; - + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; }; + + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + } namespace Catch { @@ -521,27 +629,32 @@ struct NameAndDesc { const char* description; }; +void registerTestCase + ( ITestCase* testCase, + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ); + struct AutoReg { - AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ); + AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); template - AutoReg( void (C::*method)(), - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - registerTestCase( new MethodTestCase( method ), - className, - nameAndDesc, - lineInfo ); - } + AutoReg + ( void (C::*method)(), + char const* className, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - void registerTestCase( ITestCase* testCase, - char const* className, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ); + registerTestCase + ( new MethodTestCase( method ), + className, + nameAndDesc, + lineInfo ); + } ~AutoReg(); @@ -550,6 +663,11 @@ private: void operator= ( AutoReg const& ); }; +void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ); + } // end namespace Catch #ifdef CATCH_CONFIG_VARIADIC_MACROS @@ -573,6 +691,10 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); + #else /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \ @@ -594,6 +716,9 @@ private: } \ void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test() + /////////////////////////////////////////////////////////////////////////////// + #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, Name, Desc ) \ + Catch::AutoReg( Function, CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); #endif // #included from: internal/catch_capture.hpp @@ -637,11 +762,11 @@ namespace Catch { // ResultDisposition::Flags enum struct ResultDisposition { enum Flags { - Normal = 0x00, + Normal = 0x01, - ContinueOnFailure = 0x01, // Failures fail test, but execution continues - FalseTest = 0x02, // Prefix expression with ! - SuppressFail = 0x04 // Failures are reported but do not fail the test + ContinueOnFailure = 0x02, // Failures fail test, but execution continues + FalseTest = 0x04, // Prefix expression with ! + SuppressFail = 0x08 // Failures are reported but do not fail the test }; }; inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) { @@ -689,7 +814,7 @@ namespace Catch { AssertionResult(); AssertionResult( AssertionInfo const& info, AssertionResultData const& data ); ~AssertionResult(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionResult( AssertionResult const& ) = default; AssertionResult( AssertionResult && ) = default; AssertionResult& operator = ( AssertionResult const& ) = default; @@ -716,6 +841,323 @@ namespace Catch { } // end namespace Catch +// #included from: catch_matchers.hpp +#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED + +namespace Catch { +namespace Matchers { + namespace Impl { + + namespace Generic { + template class AllOf; + template class AnyOf; + template class Not; + } + + template + struct Matcher : SharedImpl + { + typedef ExpressionT ExpressionType; + + virtual ~Matcher() {} + virtual Ptr clone() const = 0; + virtual bool match( ExpressionT const& expr ) const = 0; + virtual std::string toString() const = 0; + + Generic::AllOf operator && ( Matcher const& other ) const; + Generic::AnyOf operator || ( Matcher const& other ) const; + Generic::Not operator ! () const; + }; + + template + struct MatcherImpl : Matcher { + + virtual Ptr > clone() const { + return Ptr >( new DerivedT( static_cast( *this ) ) ); + } + }; + + namespace Generic { + template + class Not : public MatcherImpl, ExpressionT> { + public: + explicit Not( Matcher const& matcher ) : m_matcher(matcher.clone()) {} + Not( Not const& other ) : m_matcher( other.m_matcher ) {} + + virtual bool match( ExpressionT const& expr ) const CATCH_OVERRIDE { + return !m_matcher->match( expr ); + } + + virtual std::string toString() const CATCH_OVERRIDE { + return "not " + m_matcher->toString(); + } + private: + Ptr< Matcher > m_matcher; + }; + + template + class AllOf : public MatcherImpl, ExpressionT> { + public: + + AllOf() {} + AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} + + AllOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( !m_matchers[i]->match( expr ) ) + return false; + return true; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " and "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AllOf operator && ( Matcher const& other ) const { + AllOf allOfExpr( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + template + class AnyOf : public MatcherImpl, ExpressionT> { + public: + + AnyOf() {} + AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} + + AnyOf& add( Matcher const& matcher ) { + m_matchers.push_back( matcher.clone() ); + return *this; + } + virtual bool match( ExpressionT const& expr ) const + { + for( std::size_t i = 0; i < m_matchers.size(); ++i ) + if( m_matchers[i]->match( expr ) ) + return true; + return false; + } + virtual std::string toString() const { + std::ostringstream oss; + oss << "( "; + for( std::size_t i = 0; i < m_matchers.size(); ++i ) { + if( i != 0 ) + oss << " or "; + oss << m_matchers[i]->toString(); + } + oss << " )"; + return oss.str(); + } + + AnyOf operator || ( Matcher const& other ) const { + AnyOf anyOfExpr( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + private: + std::vector > > m_matchers; + }; + + } // namespace Generic + + template + Generic::AllOf Matcher::operator && ( Matcher const& other ) const { + Generic::AllOf allOfExpr; + allOfExpr.add( *this ); + allOfExpr.add( other ); + return allOfExpr; + } + + template + Generic::AnyOf Matcher::operator || ( Matcher const& other ) const { + Generic::AnyOf anyOfExpr; + anyOfExpr.add( *this ); + anyOfExpr.add( other ); + return anyOfExpr; + } + + template + Generic::Not Matcher::operator ! () const { + return Generic::Not( *this ); + } + + namespace StdString { + + inline std::string makeString( std::string const& str ) { return str; } + inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } + + struct CasedString + { + CasedString( std::string const& str, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_str( adjustString( str ) ) + {} + std::string adjustString( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No + ? toLower( str ) + : str; + + } + std::string toStringSuffix() const + { + return m_caseSensitivity == CaseSensitive::No + ? " (case insensitive)" + : ""; + } + CaseSensitive::Choice m_caseSensitivity; + std::string m_str; + }; + + struct Equals : MatcherImpl { + Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( str, caseSensitivity ) + {} + Equals( Equals const& other ) : m_data( other.m_data ){} + + virtual ~Equals(); + + virtual bool match( std::string const& expr ) const { + return m_data.m_str == m_data.adjustString( expr );; + } + virtual std::string toString() const { + return "equals: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct Contains : MatcherImpl { + Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + Contains( Contains const& other ) : m_data( other.m_data ){} + + virtual ~Contains(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) != std::string::npos; + } + virtual std::string toString() const { + return "contains: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct StartsWith : MatcherImpl { + StartsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + + StartsWith( StartsWith const& other ) : m_data( other.m_data ){} + + virtual ~StartsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == 0; + } + virtual std::string toString() const { + return "starts with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + + struct EndsWith : MatcherImpl { + EndsWith( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) + : m_data( substr, caseSensitivity ){} + EndsWith( EndsWith const& other ) : m_data( other.m_data ){} + + virtual ~EndsWith(); + + virtual bool match( std::string const& expr ) const { + return m_data.adjustString( expr ).find( m_data.m_str ) == expr.size() - m_data.m_str.size(); + } + virtual std::string toString() const { + return "ends with: \"" + m_data.m_str + "\"" + m_data.toStringSuffix(); + } + + CasedString m_data; + }; + } // namespace StdString + } // namespace Impl + + // The following functions create the actual matcher objects. + // This allows the types to be inferred + template + inline Impl::Generic::Not Not( Impl::Matcher const& m ) { + return Impl::Generic::Not( m ); + } + + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ); + } + template + inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, + Impl::Matcher const& m2, + Impl::Matcher const& m3 ) { + return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); + } + + inline Impl::StdString::Equals Equals( std::string const& str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( str, caseSensitivity ); + } + inline Impl::StdString::Equals Equals( const char* str, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Equals( Impl::StdString::makeString( str ), caseSensitivity ); + } + inline Impl::StdString::Contains Contains( std::string const& substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( substr, caseSensitivity ); + } + inline Impl::StdString::Contains Contains( const char* substr, CaseSensitive::Choice caseSensitivity = CaseSensitive::Yes ) { + return Impl::StdString::Contains( Impl::StdString::makeString( substr ), caseSensitivity ); + } + inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { + return Impl::StdString::StartsWith( substr ); + } + inline Impl::StdString::StartsWith StartsWith( const char* substr ) { + return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); + } + inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { + return Impl::StdString::EndsWith( substr ); + } + inline Impl::StdString::EndsWith EndsWith( const char* substr ) { + return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); + } + +} // namespace Matchers + +using namespace Matchers; + +} // namespace Catch + namespace Catch { struct TestFailureException{}; @@ -742,11 +1184,12 @@ namespace Catch { ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ); + ResultDisposition::Flags resultDisposition, + char const* secondArg = "" ); template - ExpressionLhs operator->* ( T const& operand ); - ExpressionLhs operator->* ( bool value ); + ExpressionLhs operator <= ( T const& operand ); + ExpressionLhs operator <= ( bool value ); template ResultBuilder& operator << ( T const& value ) { @@ -771,6 +1214,9 @@ namespace Catch { void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal ); void captureResult( ResultWas::OfType resultType ); void captureExpression(); + void captureExpectedException( std::string const& expectedMessage ); + void captureExpectedException( Matchers::Impl::Matcher const& matcher ); + void handleResult( AssertionResult const& result ); void react(); bool shouldDebugBreak() const; bool allowThrows() const; @@ -949,13 +1395,51 @@ namespace Internal { return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG + // long long to unsigned X + template bool compare( long long lhs, unsigned int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( long long lhs, unsigned char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // unsigned long long to X + template bool compare( unsigned long long lhs, int rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, long long rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + template bool compare( unsigned long long lhs, char rhs ) { + return applyEvaluator( static_cast( lhs ), rhs ); + } + + // pointer to long long (when comparing against NULL) + template bool compare( long long lhs, T* rhs ) { + return Evaluator::evaluate( reinterpret_cast( lhs ), rhs ); + } + template bool compare( T* lhs, long long rhs ) { + return Evaluator::evaluate( lhs, reinterpret_cast( rhs ) ); + } +#endif // CATCH_CONFIG_CPP11_LONG_LONG + #ifdef CATCH_CONFIG_CPP11_NULLPTR // pointer to nullptr_t (when comparing against nullptr) template bool compare( std::nullptr_t, T* rhs ) { - return Evaluator::evaluate( NULL, rhs ); + return Evaluator::evaluate( nullptr, rhs ); } template bool compare( T* lhs, std::nullptr_t ) { - return Evaluator::evaluate( lhs, NULL ); + return Evaluator::evaluate( lhs, nullptr ); } #endif // CATCH_CONFIG_CPP11_NULLPTR @@ -969,40 +1453,6 @@ namespace Internal { // #included from: catch_tostring.h #define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED -// #included from: catch_sfinae.hpp -#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED - -// Try to detect if the current compiler supports SFINAE - -namespace Catch { - - struct TrueType { - static const bool value = true; - typedef void Enable; - char sizer[1]; - }; - struct FalseType { - static const bool value = false; - typedef void Disable; - char sizer[2]; - }; - -#ifdef CATCH_CONFIG_SFINAE - - template struct NotABooleanExpression; - - template struct If : NotABooleanExpression {}; - template<> struct If : TrueType {}; - template<> struct If : FalseType {}; - - template struct SizedIf; - template<> struct SizedIf : TrueType {}; - template<> struct SizedIf : FalseType {}; - -#endif // CATCH_CONFIG_SFINAE - -} // end namespace Catch - #include #include #include @@ -1055,8 +1505,11 @@ inline id performOptionalSelector( id obj, SEL sel ) { #endif -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_TUPLE #include +#endif + +#ifdef CATCH_CONFIG_CPP11_IS_ENUM #include #endif @@ -1084,6 +1537,11 @@ std::string toString( char value ); std::string toString( signed char value ); std::string toString( unsigned char value ); +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ); +std::string toString( unsigned long long value ); +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ); #endif @@ -1096,34 +1554,15 @@ std::string toString( std::nullptr_t ); namespace Detail { - extern std::string unprintableString; - -// SFINAE is currently disabled by default for all compilers. -// If the non SFINAE version of IsStreamInsertable is ambiguous for you -// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE -#ifdef CATCH_CONFIG_SFINAE - - template - class IsStreamInsertableHelper { - template struct TrueIfSizeable : TrueType {}; - - template - static TrueIfSizeable dummy(T2*); - static FalseType dummy(...); - - public: - typedef SizedIf type; - }; - - template - struct IsStreamInsertable : IsStreamInsertableHelper::type {}; - -#else + extern const std::string unprintableString; struct BorgType { template BorgType( T const& ); }; + struct TrueType { char sizer[1]; }; + struct FalseType { char sizer[2]; }; + TrueType& testStreamable( std::ostream& ); FalseType testStreamable( FalseType ); @@ -1136,9 +1575,7 @@ namespace Detail { enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) }; }; -#endif - -#if defined(CATCH_CPP11_OR_GREATER) +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) template::value > @@ -1160,7 +1597,7 @@ namespace Detail { #endif template struct StringMakerBase { -#if defined(CATCH_CPP11_OR_GREATER) +#if defined(CATCH_CONFIG_CPP11_IS_ENUM) template static std::string convert( T const& v ) { @@ -1200,7 +1637,7 @@ struct StringMaker { template static std::string convert( U* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1210,7 +1647,7 @@ template struct StringMaker { static std::string convert( R C::* p ) { if( !p ) - return INTERNAL_CATCH_STRINGIFY( NULL ); + return "NULL"; else return Detail::rawMemoryToString( p ); } @@ -1233,7 +1670,7 @@ std::string toString( std::vector const& v ) { return Detail::rangeToString( v.begin(), v.end() ); } -#ifdef CATCH_CPP11_OR_GREATER +#ifdef CATCH_CONFIG_CPP11_TUPLE // toString for tuples namespace TupleDetail { @@ -1273,7 +1710,7 @@ struct StringMaker> { return os.str(); } }; -#endif +#endif // CATCH_CONFIG_CPP11_TUPLE namespace Detail { template @@ -1318,13 +1755,13 @@ namespace Catch { template class ExpressionLhs { ExpressionLhs& operator = ( ExpressionLhs const& ); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs& operator = ( ExpressionLhs && ) = delete; # endif public: ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {} -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS ExpressionLhs( ExpressionLhs const& ) = default; ExpressionLhs( ExpressionLhs && ) = default; # endif @@ -1405,11 +1842,11 @@ private: namespace Catch { template - inline ExpressionLhs ResultBuilder::operator->* ( T const& operand ) { + inline ExpressionLhs ResultBuilder::operator <= ( T const& operand ) { return ExpressionLhs( *this, operand ); } - inline ExpressionLhs ResultBuilder::operator->* ( bool value ) { + inline ExpressionLhs ResultBuilder::operator <= ( bool value ) { return ExpressionLhs( *this, value ); } @@ -1482,6 +1919,7 @@ namespace Catch { class AssertionResult; struct AssertionInfo; struct SectionInfo; + struct SectionEndInfo; struct MessageInfo; class ScopedMessageBuilder; struct Counts; @@ -1493,7 +1931,8 @@ namespace Catch { virtual void assertionEnded( AssertionResult const& result ) = 0; virtual bool sectionStarted( SectionInfo const& sectionInfo, Counts& assertions ) = 0; - virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0; + virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; virtual void pushScopedMessage( MessageInfo const& message ) = 0; virtual void popScopedMessage( MessageInfo const& message ) = 0; @@ -1581,7 +2020,7 @@ namespace Catch { do { \ Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ try { \ - ( __catchResult->*expr ).endExpression(); \ + ( __catchResult <= expr ).endExpression(); \ } \ catch( ... ) { \ __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \ @@ -1614,16 +2053,16 @@ namespace Catch { } while( Catch::alwaysFalse() ) /////////////////////////////////////////////////////////////////////////////// -#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \ +#define INTERNAL_CATCH_THROWS( expr, resultDisposition, matcher, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition, #matcher ); \ if( __catchResult.allowThrows() ) \ try { \ expr; \ __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \ } \ catch( ... ) { \ - __catchResult.captureResult( Catch::ResultWas::Ok ); \ + __catchResult.captureExpectedException( matcher ); \ } \ else \ __catchResult.captureResult( Catch::ResultWas::Ok ); \ @@ -1676,14 +2115,14 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \ do { \ - Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \ + Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg ", " #matcher, resultDisposition ); \ try { \ - std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \ + std::string matcherAsString = (matcher).toString(); \ __catchResult \ .setLhs( Catch::toString( arg ) ) \ .setRhs( matcherAsString == Catch::Detail::unprintableString ? #matcher : matcherAsString ) \ .setOp( "matches" ) \ - .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \ + .setResultType( (matcher).match( arg ) ); \ __catchResult.captureExpression(); \ } catch( ... ) { \ __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \ @@ -1697,21 +2136,6 @@ namespace Catch { // #included from: catch_section_info.h #define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED -namespace Catch { - - struct SectionInfo { - SectionInfo - ( SourceLineInfo const& _lineInfo, - std::string const& _name, - std::string const& _description = std::string() ); - - std::string name; - std::string description; - SourceLineInfo lineInfo; - }; - -} // end namespace Catch - // #included from: catch_totals.hpp #define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED @@ -1782,6 +2206,31 @@ namespace Catch { }; } +namespace Catch { + + struct SectionInfo { + SectionInfo + ( SourceLineInfo const& _lineInfo, + std::string const& _name, + std::string const& _description = std::string() ); + + std::string name; + std::string description; + SourceLineInfo lineInfo; + }; + + struct SectionEndInfo { + SectionEndInfo( SectionInfo const& _sectionInfo, Counts const& _prevAssertions, double _durationInSeconds ) + : sectionInfo( _sectionInfo ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) + {} + + SectionInfo sectionInfo; + Counts prevAssertions; + double durationInSeconds; + }; + +} // end namespace Catch + // #included from: catch_timer.h #define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED @@ -2022,6 +2471,8 @@ using namespace Generators; #define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED #include +#include + // #included from: catch_interfaces_registry_hub.h #define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED @@ -2046,7 +2497,8 @@ namespace Catch { struct IMutableRegistryHub { virtual ~IMutableRegistryHub(); - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0; + virtual void registerReporter( std::string const& name, Ptr const& factory ) = 0; + virtual void registerListener( Ptr const& factory ) = 0; virtual void registerTest( TestCase const& testInfo ) = 0; virtual void registerTranslator( const IExceptionTranslator* translator ) = 0; }; @@ -2058,14 +2510,16 @@ namespace Catch { } - namespace Catch { typedef std::string(*exceptionTranslateFunction)(); + struct IExceptionTranslator; + typedef std::vector ExceptionTranslators; + struct IExceptionTranslator { virtual ~IExceptionTranslator(); - virtual std::string translate() const = 0; + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0; }; struct IExceptionTranslatorRegistry { @@ -2083,9 +2537,12 @@ namespace Catch { : m_translateFunction( translateFunction ) {} - virtual std::string translate() const { + virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const CATCH_OVERRIDE { try { - throw; + if( it == itEnd ) + throw; + else + return (*it)->translate( it+1, itEnd ); } catch( T& ex ) { return m_translateFunction( ex ); @@ -2192,231 +2649,6 @@ inline std::string toString( Detail::Approx const& value ) { } // end namespace Catch -// #included from: internal/catch_matchers.hpp -#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED - -namespace Catch { -namespace Matchers { - namespace Impl { - - template - struct Matcher : SharedImpl - { - typedef ExpressionT ExpressionType; - - virtual ~Matcher() {} - virtual Ptr clone() const = 0; - virtual bool match( ExpressionT const& expr ) const = 0; - virtual std::string toString() const = 0; - }; - - template - struct MatcherImpl : Matcher { - - virtual Ptr > clone() const { - return Ptr >( new DerivedT( static_cast( *this ) ) ); - } - }; - - namespace Generic { - - template - class AllOf : public MatcherImpl, ExpressionT> { - public: - - AllOf() {} - AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {} - - AllOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( !m_matchers[i]->match( expr ) ) - return false; - return true; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " and "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - template - class AnyOf : public MatcherImpl, ExpressionT> { - public: - - AnyOf() {} - AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {} - - AnyOf& add( Matcher const& matcher ) { - m_matchers.push_back( matcher.clone() ); - return *this; - } - virtual bool match( ExpressionT const& expr ) const - { - for( std::size_t i = 0; i < m_matchers.size(); ++i ) - if( m_matchers[i]->match( expr ) ) - return true; - return false; - } - virtual std::string toString() const { - std::ostringstream oss; - oss << "( "; - for( std::size_t i = 0; i < m_matchers.size(); ++i ) { - if( i != 0 ) - oss << " or "; - oss << m_matchers[i]->toString(); - } - oss << " )"; - return oss.str(); - } - - private: - std::vector > > m_matchers; - }; - - } - - namespace StdString { - - inline std::string makeString( std::string const& str ) { return str; } - inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); } - - struct Equals : MatcherImpl { - Equals( std::string const& str ) : m_str( str ){} - Equals( Equals const& other ) : m_str( other.m_str ){} - - virtual ~Equals(); - - virtual bool match( std::string const& expr ) const { - return m_str == expr; - } - virtual std::string toString() const { - return "equals: \"" + m_str + "\""; - } - - std::string m_str; - }; - - struct Contains : MatcherImpl { - Contains( std::string const& substr ) : m_substr( substr ){} - Contains( Contains const& other ) : m_substr( other.m_substr ){} - - virtual ~Contains(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) != std::string::npos; - } - virtual std::string toString() const { - return "contains: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct StartsWith : MatcherImpl { - StartsWith( std::string const& substr ) : m_substr( substr ){} - StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~StartsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == 0; - } - virtual std::string toString() const { - return "starts with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - - struct EndsWith : MatcherImpl { - EndsWith( std::string const& substr ) : m_substr( substr ){} - EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){} - - virtual ~EndsWith(); - - virtual bool match( std::string const& expr ) const { - return expr.find( m_substr ) == expr.size() - m_substr.size(); - } - virtual std::string toString() const { - return "ends with: \"" + m_substr + "\""; - } - - std::string m_substr; - }; - } // namespace StdString - } // namespace Impl - - // The following functions create the actual matcher objects. - // This allows the types to be inferred - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AllOf AllOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AllOf().add( m1 ).add( m2 ).add( m3 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ); - } - template - inline Impl::Generic::AnyOf AnyOf( Impl::Matcher const& m1, - Impl::Matcher const& m2, - Impl::Matcher const& m3 ) { - return Impl::Generic::AnyOf().add( m1 ).add( m2 ).add( m3 ); - } - - inline Impl::StdString::Equals Equals( std::string const& str ) { - return Impl::StdString::Equals( str ); - } - inline Impl::StdString::Equals Equals( const char* str ) { - return Impl::StdString::Equals( Impl::StdString::makeString( str ) ); - } - inline Impl::StdString::Contains Contains( std::string const& substr ) { - return Impl::StdString::Contains( substr ); - } - inline Impl::StdString::Contains Contains( const char* substr ) { - return Impl::StdString::Contains( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::StartsWith StartsWith( std::string const& substr ) { - return Impl::StdString::StartsWith( substr ); - } - inline Impl::StdString::StartsWith StartsWith( const char* substr ) { - return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) ); - } - inline Impl::StdString::EndsWith EndsWith( std::string const& substr ) { - return Impl::StdString::EndsWith( substr ); - } - inline Impl::StdString::EndsWith EndsWith( const char* substr ) { - return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) ); - } - -} // namespace Matchers - -using namespace Matchers; - -} // namespace Catch - // #included from: internal/catch_interfaces_tag_alias_registry.h #define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED @@ -2450,12 +2682,12 @@ namespace Catch { template class Option { public: - Option() : nullableValue( NULL ) {} + Option() : nullableValue( CATCH_NULL ) {} Option( T const& _value ) : nullableValue( new( storage ) T( _value ) ) {} Option( Option const& _other ) - : nullableValue( _other ? new( storage ) T( *_other ) : NULL ) + : nullableValue( _other ? new( storage ) T( *_other ) : CATCH_NULL ) {} ~Option() { @@ -2479,7 +2711,7 @@ namespace Catch { void reset() { if( nullableValue ) nullableValue->~T(); - nullableValue = NULL; + nullableValue = CATCH_NULL; } T& operator*() { return *nullableValue; } @@ -2491,10 +2723,10 @@ namespace Catch { return nullableValue ? *nullableValue : defaultValue; } - bool some() const { return nullableValue != NULL; } - bool none() const { return nullableValue == NULL; } + bool some() const { return nullableValue != CATCH_NULL; } + bool none() const { return nullableValue == CATCH_NULL; } - bool operator !() const { return nullableValue == NULL; } + bool operator !() const { return nullableValue == CATCH_NULL; } operator SafeBool::type() const { return SafeBool::makeSafe( some() ); } @@ -2552,6 +2784,8 @@ namespace Catch { TestCaseInfo( TestCaseInfo const& other ); + friend void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ); + bool isHidden() const; bool throws() const; bool okToFail() const; @@ -2664,7 +2898,7 @@ namespace Catch { inline size_t registerTestMethods() { size_t noTestMethods = 0; - int noClasses = objc_getClassList( NULL, 0 ); + int noClasses = objc_getClassList( CATCH_NULL, 0 ); Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses); objc_getClassList( classes, noClasses ); @@ -2806,7 +3040,7 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wweak-vtables" #endif -// #included from: ../catch_runner.hpp +// #included from: ../catch_session.hpp #define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED // #included from: internal/catch_commandline.hpp @@ -2831,6 +3065,67 @@ return @ desc; \ #pragma clang diagnostic ignored "-Wpadded" #endif +// #included from: catch_wildcard_pattern.hpp +#define TWOBLUECUBES_CATCH_WILDCARD_PATTERN_HPP_INCLUDED + +namespace Catch +{ + class WildcardPattern { + enum WildcardPosition { + NoWildcard = 0, + WildcardAtStart = 1, + WildcardAtEnd = 2, + WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd + }; + + public: + + WildcardPattern( std::string const& pattern, CaseSensitive::Choice caseSensitivity ) + : m_caseSensitivity( caseSensitivity ), + m_wildcard( NoWildcard ), + m_pattern( adjustCase( pattern ) ) + { + if( startsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 1 ); + m_wildcard = WildcardAtStart; + } + if( endsWith( m_pattern, "*" ) ) { + m_pattern = m_pattern.substr( 0, m_pattern.size()-1 ); + m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); + } + } + virtual ~WildcardPattern(); + virtual bool matches( std::string const& str ) const { + switch( m_wildcard ) { + case NoWildcard: + return m_pattern == adjustCase( str ); + case WildcardAtStart: + return endsWith( adjustCase( str ), m_pattern ); + case WildcardAtEnd: + return startsWith( adjustCase( str ), m_pattern ); + case WildcardAtBothEnds: + return contains( adjustCase( str ), m_pattern ); + } + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunreachable-code" +#endif + throw std::logic_error( "Unknown enum" ); +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + } + private: + std::string adjustCase( std::string const& str ) const { + return m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str; + } + CaseSensitive::Choice m_caseSensitivity; + WildcardPosition m_wildcard; + std::string m_pattern; + }; +} + #include #include @@ -2842,50 +3137,18 @@ namespace Catch { virtual bool matches( TestCaseInfo const& testCase ) const = 0; }; class NamePattern : public Pattern { - enum WildcardPosition { - NoWildcard = 0, - WildcardAtStart = 1, - WildcardAtEnd = 2, - WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd - }; - public: - NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) { - if( startsWith( m_name, "*" ) ) { - m_name = m_name.substr( 1 ); - m_wildcard = WildcardAtStart; - } - if( endsWith( m_name, "*" ) ) { - m_name = m_name.substr( 0, m_name.size()-1 ); - m_wildcard = static_cast( m_wildcard | WildcardAtEnd ); - } - } + NamePattern( std::string const& name ) + : m_wildcardPattern( toLower( name ), CaseSensitive::No ) + {} virtual ~NamePattern(); virtual bool matches( TestCaseInfo const& testCase ) const { - switch( m_wildcard ) { - case NoWildcard: - return m_name == toLower( testCase.name ); - case WildcardAtStart: - return endsWith( toLower( testCase.name ), m_name ); - case WildcardAtEnd: - return startsWith( toLower( testCase.name ), m_name ); - case WildcardAtBothEnds: - return contains( toLower( testCase.name ), m_name ); - } - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunreachable-code" -#endif - throw std::logic_error( "Unknown enum" ); -#ifdef __clang__ -#pragma clang diagnostic pop -#endif + return m_wildcardPattern.matches( toLower( testCase.name ) ); } private: - std::string m_name; - WildcardPosition m_wildcard; + WildcardPattern m_wildcardPattern; }; + class TagPattern : public Pattern { public: TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {} @@ -2896,6 +3159,7 @@ namespace Catch { private: std::string m_tag; }; + class ExcludedPattern : public Pattern { public: ExcludedPattern( Ptr const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {} @@ -3093,28 +3357,62 @@ namespace Catch { // #included from: catch_stream.h #define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED -#include +// #included from: catch_streambuf.h +#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED -#ifdef __clang__ -#pragma clang diagnostic ignored "-Wpadded" -#endif +#include namespace Catch { - class Stream { + class StreamBufBase : public std::streambuf { public: - Stream(); - Stream( std::streambuf* _streamBuf, bool _isOwned ); - void release(); - - std::streambuf* streamBuf; - - private: - bool isOwned; + virtual ~StreamBufBase() CATCH_NOEXCEPT; }; +} + +#include +#include +#include + +namespace Catch { std::ostream& cout(); std::ostream& cerr(); + + struct IStream { + virtual ~IStream() CATCH_NOEXCEPT; + virtual std::ostream& stream() const = 0; + }; + + class FileStream : public IStream { + mutable std::ofstream m_ofs; + public: + FileStream( std::string const& filename ); + virtual ~FileStream() CATCH_NOEXCEPT; + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class CoutStream : public IStream { + mutable std::ostream m_os; + public: + CoutStream(); + virtual ~CoutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; + + class DebugOutStream : public IStream { + std::auto_ptr m_streamBuf; + mutable std::ostream m_os; + public: + DebugOutStream(); + virtual ~DebugOutStream() CATCH_NOEXCEPT; + + public: // IStream + virtual std::ostream& stream() const CATCH_OVERRIDE; + }; } #include @@ -3142,6 +3440,7 @@ namespace Catch { showHelp( false ), showInvisibles( false ), forceColour( false ), + filenamesAsTags( false ), abortAfter( -1 ), rngSeed( 0 ), verbosity( Verbosity::Normal ), @@ -3161,6 +3460,7 @@ namespace Catch { bool showHelp; bool showInvisibles; bool forceColour; + bool filenamesAsTags; int abortAfter; unsigned int rngSeed; @@ -3170,11 +3470,11 @@ namespace Catch { ShowDurations::OrNot showDurations; RunTests::InWhatOrder runOrder; - std::string reporterName; std::string outputFilename; std::string name; std::string processName; + std::vector reporterNames; std::vector testsOrTags; }; @@ -3186,12 +3486,11 @@ namespace Catch { public: Config() - : m_os( Catch::cout().rdbuf() ) {} Config( ConfigData const& data ) : m_data( data ), - m_os( Catch::cout().rdbuf() ) + m_stream( openStream() ) { if( !data.testsOrTags.empty() ) { TestSpecParser parser( ITagAliasRegistry::get() ); @@ -3202,12 +3501,6 @@ namespace Catch { } virtual ~Config() { - m_os.rdbuf( Catch::cout().rdbuf() ); - m_stream.release(); - } - - void setFilename( std::string const& filename ) { - m_data.outputFilename = filename; } std::string const& getFilename() const { @@ -3223,18 +3516,7 @@ namespace Catch { bool shouldDebugBreak() const { return m_data.shouldDebugBreak; } - void setStreamBuf( std::streambuf* buf ) { - m_os.rdbuf( buf ? buf : Catch::cout().rdbuf() ); - } - - void useStream( std::string const& streamName ) { - Stream stream = createStream( streamName ); - setStreamBuf( stream.streamBuf ); - m_stream.release(); - m_stream = stream; - } - - std::string getReporterName() const { return m_data.reporterName; } + std::vector getReporterNames() const { return m_data.reporterNames; } int abortAfter() const { return m_data.abortAfter; } @@ -3245,7 +3527,7 @@ namespace Catch { // IConfig interface virtual bool allowThrows() const { return !m_data.noThrow; } - virtual std::ostream& stream() const { return m_os; } + virtual std::ostream& stream() const { return m_stream->stream(); } virtual std::string name() const { return m_data.name.empty() ? m_data.processName : m_data.name; } virtual bool includeSuccessfulResults() const { return m_data.showSuccessfulTests; } virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; } @@ -3255,10 +3537,22 @@ namespace Catch { virtual bool forceColour() const { return m_data.forceColour; } private: + + IStream const* openStream() { + if( m_data.outputFilename.empty() ) + return new CoutStream(); + else if( m_data.outputFilename[0] == '%' ) { + if( m_data.outputFilename == "%debug" ) + return new DebugOutStream(); + else + throw std::domain_error( "Unrecognised stream: " + m_data.outputFilename ); + } + else + return new FileStream( m_data.outputFilename ); + } ConfigData m_data; - Stream m_stream; - mutable std::ostream m_os; + std::auto_ptr m_stream; TestSpec m_testSpec; }; @@ -3514,7 +3808,7 @@ namespace Clara { template struct IArgFunction { virtual ~IArgFunction() {} -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS IArgFunction() = default; IArgFunction( IArgFunction const& ) = default; # endif @@ -3527,11 +3821,11 @@ namespace Clara { template class BoundArgFunction { public: - BoundArgFunction() : functionObj( NULL ) {} + BoundArgFunction() : functionObj( CATCH_NULL ) {} BoundArgFunction( IArgFunction* _functionObj ) : functionObj( _functionObj ) {} - BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {} + BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : CATCH_NULL ) {} BoundArgFunction& operator = ( BoundArgFunction const& other ) { - IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL; + IArgFunction* newFunctionObj = other.functionObj ? other.functionObj->clone() : CATCH_NULL; delete functionObj; functionObj = newFunctionObj; return *this; @@ -3547,7 +3841,7 @@ namespace Clara { bool takesArg() const { return functionObj->takesArg(); } bool isSet() const { - return functionObj != NULL; + return functionObj != CATCH_NULL; } private: IArgFunction* functionObj; @@ -3765,12 +4059,7 @@ namespace Clara { } }; - // NOTE: std::auto_ptr is deprecated in c++11/c++0x -#if defined(__cplusplus) && __cplusplus > 199711L - typedef std::unique_ptr ArgAutoPtr; -#else - typedef std::auto_ptr ArgAutoPtr; -#endif + typedef CATCH_AUTO_PTR( Arg ) ArgAutoPtr; friend void addOptName( Arg& arg, std::string const& optName ) { @@ -3846,8 +4135,8 @@ namespace Clara { m_arg->description = description; return *this; } - ArgBuilder& detail( std::string const& detail ) { - m_arg->detail = detail; + ArgBuilder& detail( std::string const& _detail ) { + m_arg->detail = _detail; return *this; } @@ -3930,14 +4219,14 @@ namespace Clara { maxWidth = (std::max)( maxWidth, it->commands().size() ); for( it = itBegin; it != itEnd; ++it ) { - Detail::Text usage( it->commands(), Detail::TextAttributes() + Detail::Text usageText( it->commands(), Detail::TextAttributes() .setWidth( maxWidth+indent ) .setIndent( indent ) ); Detail::Text desc( it->description, Detail::TextAttributes() .setWidth( width - maxWidth - 3 ) ); - for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) { - std::string usageCol = i < usage.size() ? usage[i] : ""; + for( std::size_t i = 0; i < (std::max)( usageText.size(), desc.size() ); ++i ) { + std::string usageCol = i < usageText.size() ? usageText[i] : ""; os << usageCol; if( i < desc.size() && !desc[i].empty() ) @@ -4143,6 +4432,7 @@ namespace Catch { config.abortAfter = x; } inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); } + inline void addReporterName( ConfigData& config, std::string const& _reporterName ) { config.reporterNames.push_back( _reporterName ); } inline void addWarning( ConfigData& config, std::string const& _warning ) { if( _warning == "NoAssertions" ) @@ -4236,7 +4526,7 @@ namespace Catch { cli["-r"]["--reporter"] // .placeholder( "name[:filename]" ) .describe( "reporter to use (defaults to console)" ) - .bind( &ConfigData::reporterName, "name" ); + .bind( &addReporterName, "name" ); cli["-n"]["--name"] .describe( "suite name" ) @@ -4273,6 +4563,10 @@ namespace Catch { .describe( "load test names to run from a file" ) .bind( &loadTestNamesFromFile, "filename" ); + cli["-#"]["--filenames-as-tags"] + .describe( "adds a tag for the filename" ) + .bind( &ConfigData::filenamesAsTags ); + // Less common commands which don't have a short form cli["--list-test-names-only"] .describe( "list all/matching test cases names only" ) @@ -4530,18 +4824,18 @@ namespace Catch { namespace Catch { struct ReporterConfig { - explicit ReporterConfig( Ptr const& _fullConfig ) + explicit ReporterConfig( Ptr const& _fullConfig ) : m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {} - ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) + ReporterConfig( Ptr const& _fullConfig, std::ostream& _stream ) : m_stream( &_stream ), m_fullConfig( _fullConfig ) {} std::ostream& stream() const { return *m_stream; } - Ptr fullConfig() const { return m_fullConfig; } + Ptr fullConfig() const { return m_fullConfig; } private: std::ostream* m_stream; - Ptr m_fullConfig; + Ptr m_fullConfig; }; struct ReporterPreferences { @@ -4605,7 +4899,7 @@ namespace Catch } virtual ~AssertionStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS AssertionStats( AssertionStats const& ) = default; AssertionStats( AssertionStats && ) = default; AssertionStats& operator = ( AssertionStats const& ) = default; @@ -4628,7 +4922,7 @@ namespace Catch missingAssertions( _missingAssertions ) {} virtual ~SectionStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS SectionStats( SectionStats const& ) = default; SectionStats( SectionStats && ) = default; SectionStats& operator = ( SectionStats const& ) = default; @@ -4655,7 +4949,7 @@ namespace Catch {} virtual ~TestCaseStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestCaseStats( TestCaseStats const& ) = default; TestCaseStats( TestCaseStats && ) = default; TestCaseStats& operator = ( TestCaseStats const& ) = default; @@ -4683,7 +4977,7 @@ namespace Catch {} virtual ~TestGroupStats(); -# ifdef CATCH_CPP11_OR_GREATER +# ifdef CATCH_CONFIG_CPP11_GENERATED_METHODS TestGroupStats( TestGroupStats const& ) = default; TestGroupStats( TestGroupStats && ) = default; TestGroupStats& operator = ( TestGroupStats const& ) = default; @@ -4705,7 +4999,7 @@ namespace Catch {} virtual ~TestRunStats(); -# ifndef CATCH_CPP11_OR_GREATER +# ifndef CATCH_CONFIG_CPP11_GENERATED_METHODS TestRunStats( TestRunStats const& _other ) : runInfo( _other.runInfo ), totals( _other.totals ), @@ -4743,6 +5037,7 @@ namespace Catch // The return value indicates if the messages buffer should be cleared: virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0; + virtual void sectionEnded( SectionStats const& sectionStats ) = 0; virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0; virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0; @@ -4751,20 +5046,24 @@ namespace Catch virtual void skipTest( TestCaseInfo const& testInfo ) = 0; }; - struct IReporterFactory { + struct IReporterFactory : IShared { virtual ~IReporterFactory(); virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0; virtual std::string getDescription() const = 0; }; struct IReporterRegistry { - typedef std::map FactoryMap; + typedef std::map > FactoryMap; + typedef std::vector > Listeners; virtual ~IReporterRegistry(); - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const = 0; virtual FactoryMap const& getFactories() const = 0; + virtual Listeners const& getListeners() const = 0; }; + Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ); + } #include @@ -4787,8 +5086,7 @@ namespace Catch { nameAttr.setInitialIndent( 2 ).setIndent( 4 ); tagsAttr.setIndent( 6 ); - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4816,8 +5114,7 @@ namespace Catch { if( !config.testSpec().hasFilters() ) testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec(); std::size_t matchedTests = 0; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4857,8 +5154,7 @@ namespace Catch { std::map tagCounts; - std::vector matchedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases ); + std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( std::vector::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end(); it != itEnd; ++it ) { @@ -4929,7 +5225,7 @@ namespace Catch { } // end namespace Catch -// #included from: internal/catch_runner_impl.hpp +// #included from: internal/catch_run_context.hpp #define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED // #included from: catch_test_case_tracker.hpp @@ -4938,132 +5234,300 @@ namespace Catch { #include #include #include +#include namespace Catch { -namespace SectionTracking { +namespace TestCaseTracking { - class TrackedSection { + struct ITracker : SharedImpl<> { + virtual ~ITracker(); - typedef std::map TrackedSections; + // static queries + virtual std::string name() const = 0; + + // dynamic queries + virtual bool isComplete() const = 0; // Successfully completed or failed + virtual bool isSuccessfullyCompleted() const = 0; + virtual bool isOpen() const = 0; // Started but not complete + virtual bool hasChildren() const = 0; + + virtual ITracker& parent() = 0; + + // actions + virtual void close() = 0; // Successfully complete + virtual void fail() = 0; + virtual void markAsNeedingAnotherRun() = 0; + + virtual void addChild( Ptr const& child ) = 0; + virtual ITracker* findChild( std::string const& name ) = 0; + virtual void openChild() = 0; + }; + + class TrackerContext { - public: enum RunState { NotStarted, Executing, - ExecutingChildren, - Completed + CompletedCycle }; - TrackedSection( std::string const& name, TrackedSection* parent ) - : m_name( name ), m_runState( NotStarted ), m_parent( parent ) + Ptr m_rootTracker; + ITracker* m_currentTracker; + RunState m_runState; + + public: + + static TrackerContext& instance() { + static TrackerContext s_instance; + return s_instance; + } + + TrackerContext() + : m_currentTracker( CATCH_NULL ), + m_runState( NotStarted ) {} - RunState runState() const { return m_runState; } + ITracker& startRun(); - TrackedSection* findChild( std::string const& childName ) { - TrackedSections::iterator it = m_children.find( childName ); - return it != m_children.end() - ? &it->second - : NULL; + void endRun() { + m_rootTracker.reset(); + m_currentTracker = CATCH_NULL; + m_runState = NotStarted; } - TrackedSection* acquireChild( std::string const& childName ) { - if( TrackedSection* child = findChild( childName ) ) - return child; - m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) ); - return findChild( childName ); + + void startCycle() { + m_currentTracker = m_rootTracker.get(); + m_runState = Executing; } - void enter() { - if( m_runState == NotStarted ) - m_runState = Executing; + void completeCycle() { + m_runState = CompletedCycle; } - void leave() { - for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end(); - it != itEnd; - ++it ) - if( it->second.runState() != Completed ) { - m_runState = ExecutingChildren; - return; - } - m_runState = Completed; + + bool completedCycle() const { + return m_runState == CompletedCycle; } - TrackedSection* getParent() { - return m_parent; + ITracker& currentTracker() { + return *m_currentTracker; } - bool hasChildren() const { + void setCurrentTracker( ITracker* tracker ) { + m_currentTracker = tracker; + } + }; + + class TrackerBase : public ITracker { + protected: + enum CycleState { + NotStarted, + Executing, + ExecutingChildren, + NeedsAnotherRun, + CompletedSuccessfully, + Failed + }; + class TrackerHasName { + std::string m_name; + public: + TrackerHasName( std::string const& name ) : m_name( name ) {} + bool operator ()( Ptr const& tracker ) { + return tracker->name() == m_name; + } + }; + typedef std::vector > Children; + std::string m_name; + TrackerContext& m_ctx; + ITracker* m_parent; + Children m_children; + CycleState m_runState; + public: + TrackerBase( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : m_name( name ), + m_ctx( ctx ), + m_parent( parent ), + m_runState( NotStarted ) + {} + virtual ~TrackerBase(); + + virtual std::string name() const CATCH_OVERRIDE { + return m_name; + } + virtual bool isComplete() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully || m_runState == Failed; + } + virtual bool isSuccessfullyCompleted() const CATCH_OVERRIDE { + return m_runState == CompletedSuccessfully; + } + virtual bool isOpen() const CATCH_OVERRIDE { + return m_runState != NotStarted && !isComplete(); + } + virtual bool hasChildren() const CATCH_OVERRIDE { return !m_children.empty(); } - private: - std::string m_name; - RunState m_runState; - TrackedSections m_children; - TrackedSection* m_parent; + virtual void addChild( Ptr const& child ) CATCH_OVERRIDE { + m_children.push_back( child ); + } + virtual ITracker* findChild( std::string const& name ) CATCH_OVERRIDE { + Children::const_iterator it = std::find_if( m_children.begin(), m_children.end(), TrackerHasName( name ) ); + return( it != m_children.end() ) + ? it->get() + : CATCH_NULL; + } + virtual ITracker& parent() CATCH_OVERRIDE { + assert( m_parent ); // Should always be non-null except for root + return *m_parent; + } + + virtual void openChild() CATCH_OVERRIDE { + if( m_runState != ExecutingChildren ) { + m_runState = ExecutingChildren; + if( m_parent ) + m_parent->openChild(); + } + } + void open() { + m_runState = Executing; + moveToThis(); + if( m_parent ) + m_parent->openChild(); + } + + virtual void close() CATCH_OVERRIDE { + + // Close any still open children (e.g. generators) + while( &m_ctx.currentTracker() != this ) + m_ctx.currentTracker().close(); + + switch( m_runState ) { + case NotStarted: + case CompletedSuccessfully: + case Failed: + throw std::logic_error( "Illogical state" ); + + case NeedsAnotherRun: + break;; + + case Executing: + m_runState = CompletedSuccessfully; + break; + case ExecutingChildren: + if( m_children.empty() || m_children.back()->isComplete() ) + m_runState = CompletedSuccessfully; + break; + + default: + throw std::logic_error( "Unexpected state" ); + } + moveToParent(); + m_ctx.completeCycle(); + } + virtual void fail() CATCH_OVERRIDE { + m_runState = Failed; + if( m_parent ) + m_parent->markAsNeedingAnotherRun(); + moveToParent(); + m_ctx.completeCycle(); + } + virtual void markAsNeedingAnotherRun() CATCH_OVERRIDE { + m_runState = NeedsAnotherRun; + } + private: + void moveToParent() { + assert( m_parent ); + m_ctx.setCurrentTracker( m_parent ); + } + void moveToThis() { + m_ctx.setCurrentTracker( this ); + } }; - class TestCaseTracker { + class SectionTracker : public TrackerBase { public: - TestCaseTracker( std::string const& testCaseName ) - : m_testCase( testCaseName, NULL ), - m_currentSection( &m_testCase ), - m_completedASectionThisRun( false ) + SectionTracker( std::string const& name, TrackerContext& ctx, ITracker* parent ) + : TrackerBase( name, ctx, parent ) {} + virtual ~SectionTracker(); - bool enterSection( std::string const& name ) { - TrackedSection* child = m_currentSection->acquireChild( name ); - if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed ) - return false; + static SectionTracker& acquire( TrackerContext& ctx, std::string const& name ) { + SectionTracker* section = CATCH_NULL; - m_currentSection = child; - m_currentSection->enter(); - return true; - } - void leaveSection() { - m_currentSection->leave(); - m_currentSection = m_currentSection->getParent(); - assert( m_currentSection != NULL ); - m_completedASectionThisRun = true; - } - - bool currentSectionHasChildren() const { - return m_currentSection->hasChildren(); - } - bool isCompleted() const { - return m_testCase.runState() == TrackedSection::Completed; - } - - class Guard { - public: - Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) { - m_tracker.enterTestCase(); + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + section = dynamic_cast( childTracker ); + assert( section ); } - ~Guard() { - m_tracker.leaveTestCase(); + else { + section = new SectionTracker( name, ctx, ¤tTracker ); + currentTracker.addChild( section ); } - private: - Guard( Guard const& ); - void operator = ( Guard const& ); - TestCaseTracker& m_tracker; - }; + if( !ctx.completedCycle() && !section->isComplete() ) { - private: - void enterTestCase() { - m_currentSection = &m_testCase; - m_completedASectionThisRun = false; - m_testCase.enter(); + section->open(); + } + return *section; } - void leaveTestCase() { - m_testCase.leave(); - } - - TrackedSection m_testCase; - TrackedSection* m_currentSection; - bool m_completedASectionThisRun; }; -} // namespace SectionTracking + class IndexTracker : public TrackerBase { + int m_size; + int m_index; + public: + IndexTracker( std::string const& name, TrackerContext& ctx, ITracker* parent, int size ) + : TrackerBase( name, ctx, parent ), + m_size( size ), + m_index( -1 ) + {} + virtual ~IndexTracker(); -using SectionTracking::TestCaseTracker; + static IndexTracker& acquire( TrackerContext& ctx, std::string const& name, int size ) { + IndexTracker* tracker = CATCH_NULL; + + ITracker& currentTracker = ctx.currentTracker(); + if( ITracker* childTracker = currentTracker.findChild( name ) ) { + tracker = dynamic_cast( childTracker ); + assert( tracker ); + } + else { + tracker = new IndexTracker( name, ctx, ¤tTracker, size ); + currentTracker.addChild( tracker ); + } + + if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( tracker->m_runState != ExecutingChildren && tracker->m_runState != NeedsAnotherRun ) + tracker->moveNext(); + tracker->open(); + } + + return *tracker; + } + + int index() const { return m_index; } + + void moveNext() { + m_index++; + m_children.clear(); + } + + virtual void close() CATCH_OVERRIDE { + TrackerBase::close(); + if( m_runState == CompletedSuccessfully && m_index < m_size-1 ) + m_runState = Executing; + } + }; + + inline ITracker& TrackerContext::startRun() { + m_rootTracker = new SectionTracker( "{root}", *this, CATCH_NULL ); + m_currentTracker = CATCH_NULL; + m_runState = Executing; + return *m_rootTracker; + } + +} // namespace TestCaseTracking + +using TestCaseTracking::ITracker; +using TestCaseTracking::TrackerContext; +using TestCaseTracking::SectionTracker; +using TestCaseTracking::IndexTracker; } // namespace Catch @@ -5179,15 +5643,12 @@ namespace Catch { public: - explicit RunContext( Ptr const& config, Ptr const& reporter ) - : m_runInfo( config->name() ), + explicit RunContext( Ptr const& _config, Ptr const& reporter ) + : m_runInfo( _config->name() ), m_context( getCurrentMutableContext() ), - m_activeTestCase( NULL ), - m_config( config ), - m_reporter( reporter ), - m_prevRunner( m_context.getRunner() ), - m_prevResultCapture( m_context.getResultCapture() ), - m_prevConfig( m_context.getConfig() ) + m_activeTestCase( CATCH_NULL ), + m_config( _config ), + m_reporter( reporter ) { m_context.setRunner( this ); m_context.setConfig( m_config ); @@ -5197,10 +5658,6 @@ namespace Catch { virtual ~RunContext() { m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) ); - m_context.setRunner( m_prevRunner ); - m_context.setConfig( NULL ); - m_context.setResultCapture( m_prevResultCapture ); - m_context.setConfig( m_prevConfig ); } void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) { @@ -5221,14 +5678,17 @@ namespace Catch { m_reporter->testCaseStarting( testInfo ); m_activeTestCase = &testCase; - m_testCaseTracker = TestCaseTracker( testInfo.name ); do { + m_trackerContext.startRun(); do { + m_trackerContext.startCycle(); + m_testCaseTracker = &SectionTracker::acquire( m_trackerContext, testInfo.name ); runCurrentTest( redirectedCout, redirectedCerr ); } - while( !m_testCaseTracker->isCompleted() && !aborting() ); + while( !m_testCaseTracker->isSuccessfullyCompleted() && !aborting() ); } + // !TBD: deprecated - this will be replaced by indexed trackers while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() ); Totals deltaTotals = m_totals.delta( prevTotals ); @@ -5239,8 +5699,8 @@ namespace Catch { redirectedCerr, aborting() ) ); - m_activeTestCase = NULL; - m_testCaseTracker.reset(); + m_activeTestCase = CATCH_NULL; + m_testCaseTracker = CATCH_NULL; return deltaTotals; } @@ -5275,8 +5735,10 @@ namespace Catch { std::ostringstream oss; oss << sectionInfo.name << "@" << sectionInfo.lineInfo; - if( !m_testCaseTracker->enterSection( oss.str() ) ) + ITracker& sectionTracker = SectionTracker::acquire( m_trackerContext, oss.str() ); + if( !sectionTracker.isOpen() ) return false; + m_activeSections.push_back( §ionTracker ); m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo; @@ -5287,30 +5749,40 @@ namespace Catch { return true; } bool testForMissingAssertions( Counts& assertions ) { - if( assertions.total() != 0 || - !m_config->warnAboutMissingAssertions() || - m_testCaseTracker->currentSectionHasChildren() ) + if( assertions.total() != 0 ) + return false; + if( !m_config->warnAboutMissingAssertions() ) + return false; + if( m_trackerContext.currentTracker().hasChildren() ) return false; m_totals.assertions.failed++; assertions.failed++; return true; } - virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) { - if( std::uncaught_exception() ) { - m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) ); - return; - } - - Counts assertions = m_totals.assertions - prevAssertions; + virtual void sectionEnded( SectionEndInfo const& endInfo ) { + Counts assertions = m_totals.assertions - endInfo.prevAssertions; bool missingAssertions = testForMissingAssertions( assertions ); - m_testCaseTracker->leaveSection(); + if( !m_activeSections.empty() ) { + m_activeSections.back()->close(); + m_activeSections.pop_back(); + } - m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) ); + m_reporter->sectionEnded( SectionStats( endInfo.sectionInfo, assertions, endInfo.durationInSeconds, missingAssertions ) ); m_messages.clear(); } + virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) { + if( m_unfinishedSections.empty() ) + m_activeSections.back()->fail(); + else + m_activeSections.back()->close(); + m_activeSections.pop_back(); + + m_unfinishedSections.push_back( endInfo ); + } + virtual void pushScopedMessage( MessageInfo const& message ) { m_messages.push_back( message ); } @@ -5376,7 +5848,8 @@ namespace Catch { double duration = 0; try { m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal ); - TestCaseTracker::Guard guard( *m_testCaseTracker ); + + seedRng( *m_config ); Timer timer; timer.start(); @@ -5396,6 +5869,7 @@ namespace Catch { catch(...) { makeUnexpectedResultBuilder().useActiveException(); } + m_testCaseTracker->close(); handleUnfinishedSections(); m_messages.clear(); @@ -5430,39 +5904,29 @@ namespace Catch { void handleUnfinishedSections() { // If sections ended prematurely due to an exception we stored their // infos here so we can tear them down outside the unwind process. - for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), + for( std::vector::const_reverse_iterator it = m_unfinishedSections.rbegin(), itEnd = m_unfinishedSections.rend(); it != itEnd; ++it ) - sectionEnded( it->info, it->prevAssertions, it->durationInSeconds ); + sectionEnded( *it ); m_unfinishedSections.clear(); } - struct UnfinishedSections { - UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds ) - : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds ) - {} - - SectionInfo info; - Counts prevAssertions; - double durationInSeconds; - }; - TestRunInfo m_runInfo; IMutableContext& m_context; TestCase const* m_activeTestCase; - Option m_testCaseTracker; + ITracker* m_testCaseTracker; + ITracker* m_currentSectionTracker; AssertionResult m_lastResult; Ptr m_config; Totals m_totals; Ptr m_reporter; std::vector m_messages; - IRunner* m_prevRunner; - IResultCapture* m_prevResultCapture; - Ptr m_prevConfig; AssertionInfo m_lastAssertionInfo; - std::vector m_unfinishedSections; + std::vector m_unfinishedSections; + std::vector m_activeSections; + TrackerContext m_trackerContext; }; IResultCapture& getResultCapture() { @@ -5483,18 +5947,19 @@ namespace Catch { struct Version { Version( unsigned int _majorVersion, unsigned int _minorVersion, - unsigned int _buildNumber, - char const* const _branchName ) - : majorVersion( _majorVersion ), - minorVersion( _minorVersion ), - buildNumber( _buildNumber ), - branchName( _branchName ) - {} + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ); unsigned int const majorVersion; unsigned int const minorVersion; + unsigned int const patchNumber; + + // buildNumber is only used if branchName is not null + std::string const branchName; unsigned int const buildNumber; - char const* const branchName; + + friend std::ostream& operator << ( std::ostream& os, Version const& version ); private: void operator=( Version const& ); @@ -5509,89 +5974,87 @@ namespace Catch { namespace Catch { - class Runner { + Ptr createReporter( std::string const& reporterName, Ptr const& config ) { + Ptr reporter = getRegistryHub().getReporterRegistry().create( reporterName, config.get() ); + if( !reporter ) { + std::ostringstream oss; + oss << "No reporter registered with name: '" << reporterName << "'"; + throw std::domain_error( oss.str() ); + } + return reporter; + } - public: - Runner( Ptr const& config ) - : m_config( config ) - { - openStream(); - makeReporter(); + Ptr makeReporter( Ptr const& config ) { + std::vector reporters = config->getReporterNames(); + if( reporters.empty() ) + reporters.push_back( "console" ); + + Ptr reporter; + for( std::vector::const_iterator it = reporters.begin(), itEnd = reporters.end(); + it != itEnd; + ++it ) + reporter = addReporter( reporter, createReporter( *it, config ) ); + return reporter; + } + Ptr addListeners( Ptr const& config, Ptr reporters ) { + IReporterRegistry::Listeners listeners = getRegistryHub().getReporterRegistry().getListeners(); + for( IReporterRegistry::Listeners::const_iterator it = listeners.begin(), itEnd = listeners.end(); + it != itEnd; + ++it ) + reporters = addReporter(reporters, (*it)->create( ReporterConfig( config ) ) ); + return reporters; + } + + Totals runTests( Ptr const& config ) { + + Ptr iconfig = config.get(); + + Ptr reporter = makeReporter( config ); + reporter = addListeners( iconfig, reporter ); + + RunContext context( iconfig, reporter ); + + Totals totals; + + context.testGroupStarting( config->name(), 1, 1 ); + + TestSpec testSpec = config->testSpec(); + if( !testSpec.hasFilters() ) + testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests + + std::vector const& allTestCases = getAllTestCasesSorted( *iconfig ); + for( std::vector::const_iterator it = allTestCases.begin(), itEnd = allTestCases.end(); + it != itEnd; + ++it ) { + if( !context.aborting() && matchTest( *it, testSpec, *iconfig ) ) + totals += context.runTest( *it ); + else + reporter->skipTest( *it ); } - Totals runTests() { + context.testGroupEnded( iconfig->name(), totals, 1, 1 ); + return totals; + } - RunContext context( m_config.get(), m_reporter ); + void applyFilenamesAsTags( IConfig const& config ) { + std::vector const& tests = getAllTestCasesSorted( config ); + for(std::size_t i = 0; i < tests.size(); ++i ) { + TestCase& test = const_cast( tests[i] ); + std::set tags = test.tags; - Totals totals; + std::string filename = test.lineInfo.file; + std::string::size_type lastSlash = filename.find_last_of( "\\/" ); + if( lastSlash != std::string::npos ) + filename = filename.substr( lastSlash+1 ); - context.testGroupStarting( "all tests", 1, 1 ); // deprecated? + std::string::size_type lastDot = filename.find_last_of( "." ); + if( lastDot != std::string::npos ) + filename = filename.substr( 0, lastDot ); - TestSpec testSpec = m_config->testSpec(); - if( !testSpec.hasFilters() ) - testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests - - std::vector testCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases ); - - int testsRunForGroup = 0; - for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); - it != itEnd; - ++it ) { - testsRunForGroup++; - if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) { - - if( context.aborting() ) - break; - - totals += context.runTest( *it ); - m_testsAlreadyRun.insert( *it ); - } - } - std::vector skippedTestCases; - getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, skippedTestCases, true ); - - for( std::vector::const_iterator it = skippedTestCases.begin(), itEnd = skippedTestCases.end(); - it != itEnd; - ++it ) - m_reporter->skipTest( *it ); - - context.testGroupEnded( "all tests", totals, 1, 1 ); - return totals; + tags.insert( "#" + filename ); + setTags( test, tags ); } - - private: - void openStream() { - // Open output file, if specified - if( !m_config->getFilename().empty() ) { - m_ofs.open( m_config->getFilename().c_str() ); - if( m_ofs.fail() ) { - std::ostringstream oss; - oss << "Unable to open file: '" << m_config->getFilename() << "'"; - throw std::domain_error( oss.str() ); - } - m_config->setStreamBuf( m_ofs.rdbuf() ); - } - } - void makeReporter() { - std::string reporterName = m_config->getReporterName().empty() - ? "console" - : m_config->getReporterName(); - - m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() ); - if( !m_reporter ) { - std::ostringstream oss; - oss << "No reporter registered with name: '" << reporterName << "'"; - throw std::domain_error( oss.str() ); - } - } - - private: - Ptr m_config; - std::ofstream m_ofs; - Ptr m_reporter; - std::set m_testsAlreadyRun; - }; + } class Session : NonCopyable { static bool alreadyInstantiated; @@ -5614,18 +6077,13 @@ namespace Catch { } void showHelp( std::string const& processName ) { - Catch::cout() << "\nCatch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " build " - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - Catch::cout() << " (" << libraryVersion.branchName << " branch)"; - Catch::cout() << "\n"; + Catch::cout() << "\nCatch v" << libraryVersion << "\n"; m_cli.usage( Catch::cout(), processName ); Catch::cout() << "For more detail usage please see the project docs\n" << std::endl; } - int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { + int applyCommandLine( int argc, char const* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) { try { m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail ); m_unusedTokens = m_cli.parseInto( argc, argv, m_configData ); @@ -5636,9 +6094,10 @@ namespace Catch { catch( std::exception& ex ) { { Colour colourGuard( Colour::Red ); - Catch::cerr() << "\nError(s) in input:\n" - << Text( ex.what(), TextAttributes().setIndent(2) ) - << "\n\n"; + Catch::cerr() + << "\nError(s) in input:\n" + << Text( ex.what(), TextAttributes().setIndent(2) ) + << "\n\n"; } m_cli.usage( Catch::cout(), m_configData.processName ); return (std::numeric_limits::max)(); @@ -5651,7 +6110,7 @@ namespace Catch { m_config.reset(); } - int run( int argc, char* const argv[] ) { + int run( int argc, char const* const argv[] ) { int returnCode = applyCommandLine( argc, argv ); if( returnCode == 0 ) @@ -5667,15 +6126,16 @@ namespace Catch { { config(); // Force config to be constructed - std::srand( m_configData.rngSeed ); + seedRng( *m_config ); - Runner runner( m_config ); + if( m_configData.filenamesAsTags ) + applyFilenamesAsTags( *m_config ); // Handle list request if( Option listed = list( config() ) ) return static_cast( *listed ); - return static_cast( runner.runTests().assertions.failed ); + return static_cast( runTests( m_config ).assertions.failed ); } catch( std::exception& ex ) { Catch::cerr() << ex.what() << std::endl; @@ -5697,7 +6157,6 @@ namespace Catch { m_config = new Config( m_configData ); return *m_config; } - private: Clara::CommandLine m_cli; std::vector m_unusedTokens; @@ -5723,16 +6182,76 @@ namespace Catch { namespace Catch { - class TestRegistry : public ITestCaseRegistry { - struct LexSort { - bool operator() (TestCase i,TestCase j) const { return (i sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + + std::vector sorted = unsortedTestCases; + + switch( config.runOrder() ) { + case RunTests::InLexicographicalOrder: + std::sort( sorted.begin(), sorted.end(), LexSort() ); + break; + case RunTests::InRandomOrder: + { + seedRng( config ); + + RandomNumberGenerator rng; + std::random_shuffle( sorted.begin(), sorted.end(), rng ); + } + break; + case RunTests::InDeclarationOrder: + // already in declaration order + break; + } + return sorted; + } + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ) { + return testSpec.matches( testCase ) && ( config.allowThrows() || !testCase.throws() ); + } + + void enforceNoDuplicateTestCases( std::vector const& functions ) { + std::set seenFunctions; + for( std::vector::const_iterator it = functions.begin(), itEnd = functions.end(); + it != itEnd; + ++it ) { + std::pair::const_iterator, bool> prev = seenFunctions.insert( *it ); + if( !prev.second ){ + Catch::cerr() + << Colour( Colour::Red ) + << "error: TEST_CASE( \"" << it->name << "\" ) already defined.\n" + << "\tFirst seen at " << prev.first->getTestCaseInfo().lineInfo << "\n" + << "\tRedefined at " << it->getTestCaseInfo().lineInfo << std::endl; + exit(1); + } + } + } + + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ) { + std::vector filtered; + filtered.reserve( testCases.size() ); + for( std::vector::const_iterator it = testCases.begin(), itEnd = testCases.end(); + it != itEnd; + ++it ) + if( matchTest( *it, testSpec, config ) ) + filtered.push_back( *it ); + return filtered; + } + std::vector const& getAllTestCasesSorted( IConfig const& config ) { + return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config ); + } + + class TestRegistry : public ITestCaseRegistry { public: - TestRegistry() : m_unnamedCount( 0 ) {} + TestRegistry() + : m_currentSortOrder( RunTests::InDeclarationOrder ), + m_unnamedCount( 0 ) + {} virtual ~TestRegistry(); virtual void registerTest( TestCase const& testCase ) { @@ -5742,69 +6261,29 @@ namespace Catch { oss << "Anonymous test case " << ++m_unnamedCount; return registerTest( testCase.withName( oss.str() ) ); } - - if( m_functions.find( testCase ) == m_functions.end() ) { - m_functions.insert( testCase ); - m_functionsInOrder.push_back( testCase ); - if( !testCase.isHidden() ) - m_nonHiddenFunctions.push_back( testCase ); - } - else { - TestCase const& prev = *m_functions.find( testCase ); - { - Colour colourGuard( Colour::Red ); - Catch::cerr() << "error: TEST_CASE( \"" << name << "\" ) already defined.\n" - << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n" - << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl; - } - exit(1); - } + m_functions.push_back( testCase ); } virtual std::vector const& getAllTests() const { - return m_functionsInOrder; + return m_functions; } + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const { + if( m_sortedFunctions.empty() ) + enforceNoDuplicateTestCases( m_functions ); - virtual std::vector const& getAllNonHiddenTests() const { - return m_nonHiddenFunctions; - } - - virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector& matchingTestCases, bool negated = false ) const { - - for( std::vector::const_iterator it = m_functionsInOrder.begin(), - itEnd = m_functionsInOrder.end(); - it != itEnd; - ++it ) { - bool includeTest = testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ); - if( includeTest != negated ) - matchingTestCases.push_back( *it ); + if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) { + m_sortedFunctions = sortTests( config, m_functions ); + m_currentSortOrder = config.runOrder(); } - sortTests( config, matchingTestCases ); + return m_sortedFunctions; } private: - - static void sortTests( IConfig const& config, std::vector& matchingTestCases ) { - - switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( matchingTestCases.begin(), matchingTestCases.end(), LexSort() ); - break; - case RunTests::InRandomOrder: - { - RandomNumberGenerator rng; - std::random_shuffle( matchingTestCases.begin(), matchingTestCases.end(), rng ); - } - break; - case RunTests::InDeclarationOrder: - // already in declaration order - break; - } - } - std::set m_functions; - std::vector m_functionsInOrder; - std::vector m_nonHiddenFunctions; + std::vector m_functions; + mutable RunTests::InWhatOrder m_currentSortOrder; + mutable std::vector m_sortedFunctions; size_t m_unnamedCount; + std::ios_base::Init m_ostreamInit; // Forces cout/ cerr to be initialised }; /////////////////////////////////////////////////////////////////////////// @@ -5837,29 +6316,38 @@ namespace Catch { return className; } - /////////////////////////////////////////////////////////////////////////// + void registerTestCase + ( ITestCase* testCase, + char const* classOrQualifiedMethodName, + NameAndDesc const& nameAndDesc, + SourceLineInfo const& lineInfo ) { - AutoReg::AutoReg( TestFunction function, - SourceLineInfo const& lineInfo, - NameAndDesc const& nameAndDesc ) { + getMutableRegistryHub().registerTest + ( makeTestCase + ( testCase, + extractClassName( classOrQualifiedMethodName ), + nameAndDesc.name, + nameAndDesc.description, + lineInfo ) ); + } + void registerTestCaseFunction + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo ); } - AutoReg::~AutoReg() {} + /////////////////////////////////////////////////////////////////////////// - void AutoReg::registerTestCase( ITestCase* testCase, - char const* classOrQualifiedMethodName, - NameAndDesc const& nameAndDesc, - SourceLineInfo const& lineInfo ) { - - getMutableRegistryHub().registerTest - ( makeTestCase( testCase, - extractClassName( classOrQualifiedMethodName ), - nameAndDesc.name, - nameAndDesc.description, - lineInfo ) ); + AutoReg::AutoReg + ( TestFunction function, + SourceLineInfo const& lineInfo, + NameAndDesc const& nameAndDesc ) { + registerTestCaseFunction( function, lineInfo, nameAndDesc ); } + AutoReg::~AutoReg() {} + } // end namespace Catch // #included from: catch_reporter_registry.hpp @@ -5873,27 +6361,32 @@ namespace Catch { public: - virtual ~ReporterRegistry() { - deleteAllValues( m_factories ); - } + virtual ~ReporterRegistry() CATCH_OVERRIDE {} - virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const { + virtual IStreamingReporter* create( std::string const& name, Ptr const& config ) const CATCH_OVERRIDE { FactoryMap::const_iterator it = m_factories.find( name ); if( it == m_factories.end() ) - return NULL; + return CATCH_NULL; return it->second->create( ReporterConfig( config ) ); } - void registerReporter( std::string const& name, IReporterFactory* factory ) { + void registerReporter( std::string const& name, Ptr const& factory ) { m_factories.insert( std::make_pair( name, factory ) ); } + void registerListener( Ptr const& factory ) { + m_listeners.push_back( factory ); + } - FactoryMap const& getFactories() const { + virtual FactoryMap const& getFactories() const CATCH_OVERRIDE { return m_factories; } + virtual Listeners const& getListeners() const CATCH_OVERRIDE { + return m_listeners; + } private: FactoryMap m_factories; + Listeners m_listeners; }; } @@ -5921,13 +6414,13 @@ namespace Catch { #ifdef __OBJC__ // In Objective-C try objective-c exceptions first @try { - throw; + return tryTranslators(); } @catch (NSException *exception) { return Catch::toString( [exception description] ); } #else - throw; + return tryTranslators(); #endif } catch( TestFailureException& ) { @@ -5943,20 +6436,15 @@ namespace Catch { return msg; } catch(...) { - return tryTranslators( m_translators.begin() ); + return "Unknown exception"; } } - std::string tryTranslators( std::vector::const_iterator it ) const { - if( it == m_translators.end() ) - return "Unknown exception"; - - try { - return (*it)->translate(); - } - catch(...) { - return tryTranslators( it+1 ); - } + std::string tryTranslators() const { + if( m_translators.empty() ) + throw; + else + return m_translators[0]->translate( m_translators.begin()+1, m_translators.end() ); } private: @@ -5976,24 +6464,27 @@ namespace Catch { public: // IRegistryHub RegistryHub() { } - virtual IReporterRegistry const& getReporterRegistry() const { + virtual IReporterRegistry const& getReporterRegistry() const CATCH_OVERRIDE { return m_reporterRegistry; } - virtual ITestCaseRegistry const& getTestCaseRegistry() const { + virtual ITestCaseRegistry const& getTestCaseRegistry() const CATCH_OVERRIDE { return m_testCaseRegistry; } - virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() { + virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() CATCH_OVERRIDE { return m_exceptionTranslatorRegistry; } public: // IMutableRegistryHub - virtual void registerReporter( std::string const& name, IReporterFactory* factory ) { + virtual void registerReporter( std::string const& name, Ptr const& factory ) CATCH_OVERRIDE { m_reporterRegistry.registerReporter( name, factory ); } - virtual void registerTest( TestCase const& testInfo ) { + virtual void registerListener( Ptr const& factory ) CATCH_OVERRIDE { + m_reporterRegistry.registerListener( factory ); + } + virtual void registerTest( TestCase const& testInfo ) CATCH_OVERRIDE { m_testCaseRegistry.registerTest( testInfo ); } - virtual void registerTranslator( const IExceptionTranslator* translator ) { + virtual void registerTranslator( const IExceptionTranslator* translator ) CATCH_OVERRIDE { m_exceptionTranslatorRegistry.registerTranslator( translator ); } @@ -6005,7 +6496,7 @@ namespace Catch { // Single, global, instance inline RegistryHub*& getTheRegistryHub() { - static RegistryHub* theRegistryHub = NULL; + static RegistryHub* theRegistryHub = CATCH_NULL; if( !theRegistryHub ) theRegistryHub = new RegistryHub(); return theRegistryHub; @@ -6020,7 +6511,7 @@ namespace Catch { } void cleanUp() { delete getTheRegistryHub(); - getTheRegistryHub() = NULL; + getTheRegistryHub() = CATCH_NULL; cleanUpContext(); } std::string translateActiveException() { @@ -6056,19 +6547,6 @@ namespace Catch { // #included from: catch_stream.hpp #define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED -// #included from: catch_streambuf.h -#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED - -#include - -namespace Catch { - - class StreamBufBase : public std::streambuf { - public: - virtual ~StreamBufBase() CATCH_NOEXCEPT; - }; -} - #include #include #include @@ -6113,6 +6591,19 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////// + FileStream::FileStream( std::string const& filename ) { + m_ofs.open( filename.c_str() ); + if( m_ofs.fail() ) { + std::ostringstream oss; + oss << "Unable to open file: '" << filename << "'"; + throw std::domain_error( oss.str() ); + } + } + + std::ostream& FileStream::stream() const { + return m_ofs; + } + struct OutputDebugWriter { void operator()( std::string const&str ) { @@ -6120,23 +6611,26 @@ namespace Catch { } }; - Stream::Stream() - : streamBuf( NULL ), isOwned( false ) + DebugOutStream::DebugOutStream() + : m_streamBuf( new StreamBufImpl() ), + m_os( m_streamBuf.get() ) {} - Stream::Stream( std::streambuf* _streamBuf, bool _isOwned ) - : streamBuf( _streamBuf ), isOwned( _isOwned ) - {} - - void Stream::release() { - if( isOwned ) { - delete streamBuf; - streamBuf = NULL; - isOwned = false; - } + std::ostream& DebugOutStream::stream() const { + return m_os; } -#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement this functions + // Store the streambuf from cout up-front because + // cout may get redirected when running tests + CoutStream::CoutStream() + : m_os( Catch::cout().rdbuf() ) + {} + + std::ostream& CoutStream::stream() const { + return m_os; + } + +#ifndef CATCH_CONFIG_NOSTDOUT // If you #define this you must implement these functions std::ostream& cout() { return std::cout; } @@ -6150,7 +6644,7 @@ namespace Catch { class Context : public IMutableContext { - Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {} + Context() : m_config( CATCH_NULL ), m_runner( CATCH_NULL ), m_resultCapture( CATCH_NULL ) {} Context( Context const& ); void operator=( Context const& ); @@ -6196,7 +6690,7 @@ namespace Catch { m_generatorsByTestName.find( testName ); return it != m_generatorsByTestName.end() ? it->second - : NULL; + : CATCH_NULL; } IGeneratorsForTest& getGeneratorsForCurrentTest() { @@ -6217,7 +6711,7 @@ namespace Catch { }; namespace { - Context* currentContext = NULL; + Context* currentContext = CATCH_NULL; } IMutableContext& getCurrentMutableContext() { if( !currentContext ) @@ -6228,17 +6722,9 @@ namespace Catch { return getCurrentMutableContext(); } - Stream createStream( std::string const& streamName ) { - if( streamName == "stdout" ) return Stream( Catch::cout().rdbuf(), false ); - if( streamName == "stderr" ) return Stream( Catch::cerr().rdbuf(), false ); - if( streamName == "debug" ) return Stream( new StreamBufImpl, true ); - - throw std::domain_error( "Unknown stream: " + streamName ); - } - void cleanUpContext() { delete currentContext; - currentContext = NULL; + currentContext = CATCH_NULL; } } @@ -6294,12 +6780,13 @@ namespace { { CONSOLE_SCREEN_BUFFER_INFO csbiInfo; GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo ); - originalAttributes = csbiInfo.wAttributes; + originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY ); + originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY ); } virtual void use( Colour::Code _colourCode ) { switch( _colourCode ) { - case Colour::None: return setTextAttribute( originalAttributes ); + case Colour::None: return setTextAttribute( originalForegroundAttributes ); case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE ); case Colour::Red: return setTextAttribute( FOREGROUND_RED ); case Colour::Green: return setTextAttribute( FOREGROUND_GREEN ); @@ -6319,10 +6806,11 @@ namespace { private: void setTextAttribute( WORD _textAttribute ) { - SetConsoleTextAttribute( stdoutHandle, _textAttribute ); + SetConsoleTextAttribute( stdoutHandle, _textAttribute | originalBackgroundAttributes ); } HANDLE stdoutHandle; - WORD originalAttributes; + WORD originalForegroundAttributes; + WORD originalBackgroundAttributes; }; IColourImpl* platformColourInstance() { @@ -6648,6 +7136,21 @@ namespace Catch { return TestCase( _testCase, info ); } + void setTags( TestCaseInfo& testCaseInfo, std::set const& tags ) + { + testCaseInfo.tags = tags; + testCaseInfo.lcaseTags.clear(); + + std::ostringstream oss; + for( std::set::const_iterator it = tags.begin(), itEnd = tags.end(); it != itEnd; ++it ) { + oss << "[" << *it << "]"; + std::string lcaseTag = toLower( *it ); + testCaseInfo.properties = static_cast( testCaseInfo.properties | parseSpecialTag( lcaseTag ) ); + testCaseInfo.lcaseTags.insert( lcaseTag ); + } + testCaseInfo.tagsAsString = oss.str(); + } + TestCaseInfo::TestCaseInfo( std::string const& _name, std::string const& _className, std::string const& _description, @@ -6656,18 +7159,10 @@ namespace Catch { : name( _name ), className( _className ), description( _description ), - tags( _tags ), lineInfo( _lineInfo ), properties( None ) { - std::ostringstream oss; - for( std::set::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) { - oss << "[" << *it << "]"; - std::string lcaseTag = toLower( *it ); - properties = static_cast( properties | parseSpecialTag( lcaseTag ) ); - lcaseTags.insert( lcaseTag ); - } - tagsAsString = oss.str(); + setTags( *this, _tags ); } TestCaseInfo::TestCaseInfo( TestCaseInfo const& other ) @@ -6750,8 +7245,33 @@ namespace Catch { namespace Catch { - // These numbers are maintained by a script - Version libraryVersion( 1, 1, 1, "master" ); + Version::Version + ( unsigned int _majorVersion, + unsigned int _minorVersion, + unsigned int _patchNumber, + std::string const& _branchName, + unsigned int _buildNumber ) + : majorVersion( _majorVersion ), + minorVersion( _minorVersion ), + patchNumber( _patchNumber ), + branchName( _branchName ), + buildNumber( _buildNumber ) + {} + + std::ostream& operator << ( std::ostream& os, Version const& version ) { + os << version.majorVersion << "." + << version.minorVersion << "." + << version.patchNumber; + + if( !version.branchName.empty() ) { + os << "-" << version.branchName + << "." << version.buildNumber; + } + return os; + } + + Version libraryVersion( 1, 3, 2, "", 0 ); + } // #included from: catch_message.hpp @@ -6943,7 +7463,7 @@ namespace Catch { #else uint64_t getCurrentTicks() { timeval t; - gettimeofday(&t,NULL); + gettimeofday(&t,CATCH_NULL); return static_cast( t.tv_sec ) * 1000000ull + static_cast( t.tv_usec ); } #endif @@ -7042,6 +7562,14 @@ namespace Catch { return line < other.line || ( line == other.line && file < other.file ); } + void seedRng( IConfig const& config ) { + if( config.rngSeed() != 0 ) + std::srand( config.rngSeed() ); + } + unsigned int rngSeed() { + return getCurrentContext().getConfig()->rngSeed(); + } + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) { #ifndef __GNUG__ os << info.file << "(" << info.line << ")"; @@ -7081,8 +7609,13 @@ namespace Catch { } Section::~Section() { - if( m_sectionIncluded ) - getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( m_sectionIncluded ) { + SectionEndInfo endInfo( m_info, m_assertions, m_timer.getElapsedSeconds() ); + if( std::uncaught_exception() ) + getResultCapture().sectionEndedEarly( endInfo ); + else + getResultCapture().sectionEnded( endInfo ); + } } // This indicates whether the section should be executed or not @@ -7134,7 +7667,7 @@ namespace Catch { // Call sysctl. size = sizeof(info); - if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) { + if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, CATCH_NULL, 0) != 0 ) { Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl; return false; } @@ -7188,9 +7721,11 @@ namespace Catch { namespace Detail { - std::string unprintableString = "{?}"; + const std::string unprintableString = "{?}"; namespace { + const int hexThreshold = 255; + struct Endianness { enum Arch { Big, Little }; @@ -7271,19 +7806,17 @@ std::string toString( wchar_t* const value ) std::string toString( int value ) { std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; return oss.str(); } std::string toString( unsigned long value ) { std::ostringstream oss; - if( value > 8192 ) - oss << "0x" << std::hex << value; - else - oss << value; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; return oss.str(); } @@ -7332,6 +7865,23 @@ std::string toString( unsigned char value ) { return toString( static_cast( value ) ); } +#ifdef CATCH_CONFIG_CPP11_LONG_LONG +std::string toString( long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +std::string toString( unsigned long long value ) { + std::ostringstream oss; + oss << value; + if( value > Detail::hexThreshold ) + oss << " (0x" << std::hex << value << ")"; + return oss.str(); +} +#endif + #ifdef CATCH_CONFIG_CPP11_NULLPTR std::string toString( std::nullptr_t ) { return "nullptr"; @@ -7361,11 +7911,17 @@ std::string toString( std::nullptr_t ) { namespace Catch { + std::string capturedExpressionWithSecondArgument( std::string const& capturedExpression, std::string const& secondArg ) { + return secondArg.empty() || secondArg == "\"\"" + ? capturedExpression + : capturedExpression + ", " + secondArg; + } ResultBuilder::ResultBuilder( char const* macroName, SourceLineInfo const& lineInfo, char const* capturedExpression, - ResultDisposition::Flags resultDisposition ) - : m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ), + ResultDisposition::Flags resultDisposition, + char const* secondArg ) + : m_assertionInfo( macroName, lineInfo, capturedExpressionWithSecondArgument( capturedExpression, secondArg ), resultDisposition ), m_shouldDebugBreak( false ), m_shouldThrow( false ) {} @@ -7406,15 +7962,41 @@ namespace Catch { setResultType( resultType ); captureExpression(); } + void ResultBuilder::captureExpectedException( std::string const& expectedMessage ) { + if( expectedMessage.empty() ) + captureExpectedException( Matchers::Impl::Generic::AllOf() ); + else + captureExpectedException( Matchers::Equals( expectedMessage ) ); + } + + void ResultBuilder::captureExpectedException( Matchers::Impl::Matcher const& matcher ) { + + assert( m_exprComponents.testFalse == false ); + AssertionResultData data = m_data; + data.resultType = ResultWas::Ok; + data.reconstructedExpression = m_assertionInfo.capturedExpression; + + std::string actualMessage = Catch::translateActiveException(); + if( !matcher.match( actualMessage ) ) { + data.resultType = ResultWas::ExpressionFailed; + data.reconstructedExpression = actualMessage; + } + AssertionResult result( m_assertionInfo, data ); + handleResult( result ); + } void ResultBuilder::captureExpression() { AssertionResult result = build(); + handleResult( result ); + } + void ResultBuilder::handleResult( AssertionResult const& result ) + { getResultCapture().assertionEnded( result ); if( !result.isOk() ) { if( getCurrentContext().getConfig()->shouldDebugBreak() ) m_shouldDebugBreak = true; - if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal ) + if( getCurrentContext().getRunner()->aborting() || (m_assertionInfo.resultDisposition & ResultDisposition::Normal) ) m_shouldThrow = true; } } @@ -7561,6 +8143,137 @@ namespace Catch { } // end namespace Catch +// #included from: ../reporters/catch_reporter_multi.hpp +#define TWOBLUECUBES_CATCH_REPORTER_MULTI_HPP_INCLUDED + +namespace Catch { + +class MultipleReporters : public SharedImpl { + typedef std::vector > Reporters; + Reporters m_reporters; + +public: + void add( Ptr const& reporter ) { + m_reporters.push_back( reporter ); + } + +public: // IStreamingReporter + + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporters[0]->getPreferences(); + } + + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->noMatchingTestCases( spec ); + } + + virtual void testRunStarting( TestRunInfo const& testRunInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunStarting( testRunInfo ); + } + + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupStarting( groupInfo ); + } + + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseStarting( testInfo ); + } + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionStarting( sectionInfo ); + } + + virtual void assertionStarting( AssertionInfo const& assertionInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->assertionStarting( assertionInfo ); + } + + // The return value indicates if the messages buffer should be cleared: + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { + bool clearBuffer = false; + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + clearBuffer |= (*it)->assertionEnded( assertionStats ); + return clearBuffer; + } + + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->sectionEnded( sectionStats ); + } + + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testCaseEnded( testCaseStats ); + } + + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testGroupEnded( testGroupStats ); + } + + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->testRunEnded( testRunStats ); + } + + virtual void skipTest( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { + for( Reporters::const_iterator it = m_reporters.begin(), itEnd = m_reporters.end(); + it != itEnd; + ++it ) + (*it)->skipTest( testInfo ); + } +}; + +Ptr addReporter( Ptr const& existingReporter, Ptr const& additionalReporter ) { + Ptr resultingReporter; + + if( existingReporter ) { + MultipleReporters* multi = dynamic_cast( existingReporter.get() ); + if( !multi ) { + multi = new MultipleReporters; + resultingReporter = Ptr( multi ); + if( existingReporter ) + multi->add( existingReporter ); + } + else + resultingReporter = existingReporter; + multi->add( additionalReporter ); + } + else + resultingReporter = additionalReporter; + + return resultingReporter; +} + +} // end namespace Catch + // #included from: ../reporters/catch_reporter_xml.hpp #define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED @@ -7576,47 +8289,53 @@ namespace Catch { StreamingReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } - virtual ~StreamingReporterBase(); + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void noMatchingTestCases( std::string const& ) {} + virtual ~StreamingReporterBase() CATCH_OVERRIDE; - virtual void testRunStarting( TestRunInfo const& _testRunInfo ) { + virtual void noMatchingTestCases( std::string const& ) CATCH_OVERRIDE {} + + virtual void testRunStarting( TestRunInfo const& _testRunInfo ) CATCH_OVERRIDE { currentTestRunInfo = _testRunInfo; } - virtual void testGroupStarting( GroupInfo const& _groupInfo ) { + virtual void testGroupStarting( GroupInfo const& _groupInfo ) CATCH_OVERRIDE { currentGroupInfo = _groupInfo; } - virtual void testCaseStarting( TestCaseInfo const& _testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& _testInfo ) CATCH_OVERRIDE { currentTestCaseInfo = _testInfo; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_sectionStack.push_back( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) { + virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) CATCH_OVERRIDE { m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) { + virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); } - virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) { + virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) CATCH_OVERRIDE { currentGroupInfo.reset(); } - virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) { + virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) CATCH_OVERRIDE { currentTestCaseInfo.reset(); currentGroupInfo.reset(); currentTestRunInfo.reset(); } - virtual void skipTest( TestCaseInfo const& ) { + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE { // Don't do anything with this by default. // It can optionally be overridden in the derived class. } - Ptr m_config; + Ptr m_config; std::ostream& stream; LazyStat currentTestRunInfo; @@ -7624,6 +8343,7 @@ namespace Catch { LazyStat currentTestCaseInfo; std::vector m_sectionStack; + ReporterPreferences m_reporterPrefs; }; struct CumulativeReporterBase : SharedImpl { @@ -7674,15 +8394,21 @@ namespace Catch { CumulativeReporterBase( ReporterConfig const& _config ) : m_config( _config.fullConfig() ), stream( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = false; + } ~CumulativeReporterBase(); - virtual void testRunStarting( TestRunInfo const& ) {} - virtual void testGroupStarting( GroupInfo const& ) {} + virtual ReporterPreferences getPreferences() const CATCH_OVERRIDE { + return m_reporterPrefs; + } - virtual void testCaseStarting( TestCaseInfo const& ) {} + virtual void testRunStarting( TestRunInfo const& ) CATCH_OVERRIDE {} + virtual void testGroupStarting( GroupInfo const& ) CATCH_OVERRIDE {} - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void testCaseStarting( TestCaseInfo const& ) CATCH_OVERRIDE {} + + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { SectionStats incompleteStats( sectionInfo, Counts(), 0, false ); Ptr node; if( m_sectionStack.empty() ) { @@ -7707,7 +8433,7 @@ namespace Catch { m_deepestSection = node; } - virtual void assertionStarting( AssertionInfo const& ) {} + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} virtual bool assertionEnded( AssertionStats const& assertionStats ) { assert( !m_sectionStack.empty() ); @@ -7715,13 +8441,13 @@ namespace Catch { sectionNode.assertions.push_back( assertionStats ); return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { assert( !m_sectionStack.empty() ); SectionNode& node = *m_sectionStack.back(); node.stats = sectionStats; m_sectionStack.pop_back(); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { Ptr node = new TestCaseNode( testCaseStats ); assert( m_sectionStack.size() == 0 ); node->children.push_back( m_rootSection ); @@ -7732,12 +8458,12 @@ namespace Catch { m_deepestSection->stdOut = testCaseStats.stdOut; m_deepestSection->stdErr = testCaseStats.stdErr; } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { Ptr node = new TestGroupNode( testGroupStats ); node->children.swap( m_testCases ); m_testGroups.push_back( node ); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { Ptr node = new TestRunNode( testRunStats ); node->children.swap( m_testGroups ); m_testRuns.push_back( node ); @@ -7745,9 +8471,9 @@ namespace Catch { } virtual void testRunEndedCumulative() = 0; - virtual void skipTest( TestCaseInfo const& ) {} + virtual void skipTest( TestCaseInfo const& ) CATCH_OVERRIDE {} - Ptr m_config; + Ptr m_config; std::ostream& stream; std::vector m_assertions; std::vector > > m_sections; @@ -7759,6 +8485,7 @@ namespace Catch { Ptr m_rootSection; Ptr m_deepestSection; std::vector > m_sectionStack; + ReporterPreferences m_reporterPrefs; }; @@ -7772,6 +8499,17 @@ namespace Catch { return line; } + struct TestEventListenerBase : StreamingReporterBase { + TestEventListenerBase( ReporterConfig const& _config ) + : StreamingReporterBase( _config ) + {} + + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE {} + virtual bool assertionEnded( AssertionStats const& ) CATCH_OVERRIDE { + return false; + } + }; + } // end namespace Catch // #included from: ../internal/catch_reporter_registrars.hpp @@ -7802,7 +8540,7 @@ namespace Catch { template class ReporterRegistrar { - class ReporterFactory : public IReporterFactory { + class ReporterFactory : public SharedImpl { // *** Please Note ***: // - If you end up here looking at a compiler error because it's trying to register @@ -7830,22 +8568,102 @@ namespace Catch { getMutableRegistryHub().registerReporter( name, new ReporterFactory() ); } }; + + template + class ListenerRegistrar { + + class ListenerFactory : public SharedImpl { + + virtual IStreamingReporter* create( ReporterConfig const& config ) const { + return new T( config ); + } + virtual std::string getDescription() const { + return ""; + } + }; + + public: + + ListenerRegistrar() { + getMutableRegistryHub().registerListener( new ListenerFactory() ); + } + }; } #define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \ namespace{ Catch::LegacyReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } + #define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \ namespace{ Catch::ReporterRegistrar catch_internal_RegistrarFor##reporterType( name ); } +#define INTERNAL_CATCH_REGISTER_LISTENER( listenerType ) \ + namespace{ Catch::ListenerRegistrar catch_internal_RegistrarFor##listenerType; } + // #included from: ../internal/catch_xmlwriter.hpp #define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED #include #include #include +#include namespace Catch { + class XmlEncode { + public: + enum ForWhat { ForTextNodes, ForAttributes }; + + XmlEncode( std::string const& str, ForWhat forWhat = ForTextNodes ) + : m_str( str ), + m_forWhat( forWhat ) + {} + + void encodeTo( std::ostream& os ) const { + + // Apostrophe escaping not necessary if we always use " to write attributes + // (see: http://www.w3.org/TR/xml/#syntax) + + for( std::size_t i = 0; i < m_str.size(); ++ i ) { + char c = m_str[i]; + switch( c ) { + case '<': os << "<"; break; + case '&': os << "&"; break; + + case '>': + // See: http://www.w3.org/TR/xml/#syntax + if( i > 2 && m_str[i-1] == ']' && m_str[i-2] == ']' ) + os << ">"; + else + os << c; + break; + + case '\"': + if( m_forWhat == ForAttributes ) + os << """; + else + os << c; + break; + + default: + // Escape control chars - based on contribution by @espenalb in PR #465 + if ( ( c < '\x09' ) || ( c > '\x0D' && c < '\x20') || c=='\x7F' ) + os << "&#x" << std::uppercase << std::hex << static_cast( c ); + else + os << c; + } + } + } + + friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) { + xmlEncode.encodeTo( os ); + return os; + } + + private: + std::string m_str; + ForWhat m_forWhat; + }; + class XmlWriter { public: @@ -7857,7 +8675,7 @@ namespace Catch { ScopedElement( ScopedElement const& other ) : m_writer( other.m_writer ){ - other.m_writer = NULL; + other.m_writer = CATCH_NULL; } ~ScopedElement() { @@ -7897,27 +8715,6 @@ namespace Catch { endElement(); } -//# ifndef CATCH_CPP11_OR_GREATER -// XmlWriter& operator = ( XmlWriter const& other ) { -// XmlWriter temp( other ); -// swap( temp ); -// return *this; -// } -//# else -// XmlWriter( XmlWriter const& ) = default; -// XmlWriter( XmlWriter && ) = default; -// XmlWriter& operator = ( XmlWriter const& ) = default; -// XmlWriter& operator = ( XmlWriter && ) = default; -//# endif -// -// void swap( XmlWriter& other ) { -// std::swap( m_tagIsOpen, other.m_tagIsOpen ); -// std::swap( m_needsNewline, other.m_needsNewline ); -// std::swap( m_tags, other.m_tags ); -// std::swap( m_indent, other.m_indent ); -// std::swap( m_os, other.m_os ); -// } - XmlWriter& startElement( std::string const& name ) { ensureTagClosed(); newlineIfNecessary(); @@ -7949,11 +8746,8 @@ namespace Catch { } XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) { - if( !name.empty() && !attribute.empty() ) { - stream() << " " << name << "=\""; - writeEncodedText( attribute ); - stream() << "\""; - } + if( !name.empty() && !attribute.empty() ) + stream() << " " << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << "\""; return *this; } @@ -7964,9 +8758,9 @@ namespace Catch { template XmlWriter& writeAttribute( std::string const& name, T const& attribute ) { - if( !name.empty() ) - stream() << " " << name << "=\"" << attribute << "\""; - return *this; + std::ostringstream oss; + oss << attribute; + return writeAttribute( name, oss.str() ); } XmlWriter& writeText( std::string const& text, bool indent = true ) { @@ -7975,7 +8769,7 @@ namespace Catch { ensureTagClosed(); if( tagWasOpen && indent ) stream() << m_indent; - writeEncodedText( text ); + stream() << XmlEncode( text ); m_needsNewline = true; } return *this; @@ -8020,30 +8814,6 @@ namespace Catch { } } - void writeEncodedText( std::string const& text ) { - static const char* charsToEncode = "<&\""; - std::string mtext = text; - std::string::size_type pos = mtext.find_first_of( charsToEncode ); - while( pos != std::string::npos ) { - stream() << mtext.substr( 0, pos ); - - switch( mtext[pos] ) { - case '<': - stream() << "<"; - break; - case '&': - stream() << "&"; - break; - case '\"': - stream() << """; - break; - } - mtext = mtext.substr( pos+1 ); - pos = mtext.find_first_of( charsToEncode ); - } - stream() << mtext; - } - bool m_tagIsOpen; bool m_needsNewline; std::vector m_tags; @@ -8052,32 +8822,44 @@ namespace Catch { }; } +// #included from: catch_reenable_warnings.h + +#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(pop) +# else +# pragma clang diagnostic pop +# endif +#elif defined __GNUC__ +# pragma GCC diagnostic pop +#endif + + namespace Catch { class XmlReporter : public StreamingReporterBase { public: XmlReporter( ReporterConfig const& _config ) : StreamingReporterBase( _config ), m_sectionDepth( 0 ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - virtual ~XmlReporter(); + virtual ~XmlReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as an XML document"; } public: // StreamingReporterBase - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - virtual void noMatchingTestCases( std::string const& s ) { + virtual void noMatchingTestCases( std::string const& s ) CATCH_OVERRIDE { StreamingReporterBase::noMatchingTestCases( s ); } - virtual void testRunStarting( TestRunInfo const& testInfo ) { + virtual void testRunStarting( TestRunInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testRunStarting( testInfo ); m_xml.setStream( stream ); m_xml.startElement( "Catch" ); @@ -8085,13 +8867,13 @@ namespace Catch { m_xml.writeAttribute( "name", m_config->name() ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { StreamingReporterBase::testGroupStarting( groupInfo ); m_xml.startElement( "Group" ) .writeAttribute( "name", groupInfo.name ); } - virtual void testCaseStarting( TestCaseInfo const& testInfo ) { + virtual void testCaseStarting( TestCaseInfo const& testInfo ) CATCH_OVERRIDE { StreamingReporterBase::testCaseStarting(testInfo); m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) ); @@ -8099,7 +8881,7 @@ namespace Catch { m_testCaseTimer.start(); } - virtual void sectionStarting( SectionInfo const& sectionInfo ) { + virtual void sectionStarting( SectionInfo const& sectionInfo ) CATCH_OVERRIDE { StreamingReporterBase::sectionStarting( sectionInfo ); if( m_sectionDepth++ > 0 ) { m_xml.startElement( "Section" ) @@ -8108,9 +8890,9 @@ namespace Catch { } } - virtual void assertionStarting( AssertionInfo const& ) { } + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { const AssertionResult& assertionResult = assertionStats.assertionResult; // Print any info messages in tags. @@ -8181,7 +8963,7 @@ namespace Catch { return true; } - virtual void sectionEnded( SectionStats const& sectionStats ) { + virtual void sectionEnded( SectionStats const& sectionStats ) CATCH_OVERRIDE { StreamingReporterBase::sectionEnded( sectionStats ); if( --m_sectionDepth > 0 ) { XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" ); @@ -8196,7 +8978,7 @@ namespace Catch { } } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( testCaseStats ); XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" ); e.writeAttribute( "success", testCaseStats.totals.assertions.allOk() ); @@ -8207,7 +8989,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { StreamingReporterBase::testGroupEnded( testGroupStats ); // TODO: Check testGroupStats.aborting and act accordingly. m_xml.scopedElement( "OverallResults" ) @@ -8217,7 +8999,7 @@ namespace Catch { m_xml.endElement(); } - virtual void testRunEnded( TestRunStats const& testRunStats ) { + virtual void testRunEnded( TestRunStats const& testRunStats ) CATCH_OVERRIDE { StreamingReporterBase::testRunEnded( testRunStats ); m_xml.scopedElement( "OverallResults" ) .writeAttribute( "successes", testRunStats.totals.assertions.passed ) @@ -8248,28 +9030,24 @@ namespace Catch { JunitReporter( ReporterConfig const& _config ) : CumulativeReporterBase( _config ), xml( _config.stream() ) - {} + { + m_reporterPrefs.shouldRedirectStdOut = true; + } - ~JunitReporter(); + virtual ~JunitReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results in an XML format that looks like Ant's junitreport target"; } - virtual void noMatchingTestCases( std::string const& /*spec*/ ) {} + virtual void noMatchingTestCases( std::string const& /*spec*/ ) CATCH_OVERRIDE {} - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = true; - return prefs; - } - - virtual void testRunStarting( TestRunInfo const& runInfo ) { + virtual void testRunStarting( TestRunInfo const& runInfo ) CATCH_OVERRIDE { CumulativeReporterBase::testRunStarting( runInfo ); xml.startElement( "testsuites" ); } - virtual void testGroupStarting( GroupInfo const& groupInfo ) { + virtual void testGroupStarting( GroupInfo const& groupInfo ) CATCH_OVERRIDE { suiteTimer.start(); stdOutForSuite.str(""); stdErrForSuite.str(""); @@ -8277,25 +9055,25 @@ namespace Catch { CumulativeReporterBase::testGroupStarting( groupInfo ); } - virtual bool assertionEnded( AssertionStats const& assertionStats ) { + virtual bool assertionEnded( AssertionStats const& assertionStats ) CATCH_OVERRIDE { if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException ) unexpectedExceptions++; return CumulativeReporterBase::assertionEnded( assertionStats ); } - virtual void testCaseEnded( TestCaseStats const& testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& testCaseStats ) CATCH_OVERRIDE { stdOutForSuite << testCaseStats.stdOut; stdErrForSuite << testCaseStats.stdErr; CumulativeReporterBase::testCaseEnded( testCaseStats ); } - virtual void testGroupEnded( TestGroupStats const& testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& testGroupStats ) CATCH_OVERRIDE { double suiteTime = suiteTimer.getElapsedSeconds(); CumulativeReporterBase::testGroupEnded( testGroupStats ); writeGroup( *m_testGroups.back(), suiteTime ); } - virtual void testRunEndedCumulative() { + virtual void testRunEndedCumulative() CATCH_OVERRIDE { xml.endElement(); } @@ -8460,24 +9238,19 @@ namespace Catch { m_headerPrinted( false ) {} - virtual ~ConsoleReporter(); + virtual ~ConsoleReporter() CATCH_OVERRIDE; static std::string getDescription() { return "Reports test results as plain lines of text"; } - virtual ReporterPreferences getPreferences() const { - ReporterPreferences prefs; - prefs.shouldRedirectStdOut = false; - return prefs; - } - virtual void noMatchingTestCases( std::string const& spec ) { + virtual void noMatchingTestCases( std::string const& spec ) CATCH_OVERRIDE { stream << "No test cases matched '" << spec << "'" << std::endl; } - virtual void assertionStarting( AssertionInfo const& ) { + virtual void assertionStarting( AssertionInfo const& ) CATCH_OVERRIDE { } - virtual bool assertionEnded( AssertionStats const& _assertionStats ) { + virtual bool assertionEnded( AssertionStats const& _assertionStats ) CATCH_OVERRIDE { AssertionResult const& result = _assertionStats.assertionResult; bool printInfoMessages = true; @@ -8497,11 +9270,11 @@ namespace Catch { return true; } - virtual void sectionStarting( SectionInfo const& _sectionInfo ) { + virtual void sectionStarting( SectionInfo const& _sectionInfo ) CATCH_OVERRIDE { m_headerPrinted = false; StreamingReporterBase::sectionStarting( _sectionInfo ); } - virtual void sectionEnded( SectionStats const& _sectionStats ) { + virtual void sectionEnded( SectionStats const& _sectionStats ) CATCH_OVERRIDE { if( _sectionStats.missingAssertions ) { lazyPrint(); Colour colour( Colour::ResultError ); @@ -8523,11 +9296,11 @@ namespace Catch { StreamingReporterBase::sectionEnded( _sectionStats ); } - virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) { + virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) CATCH_OVERRIDE { StreamingReporterBase::testCaseEnded( _testCaseStats ); m_headerPrinted = false; } - virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) { + virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) CATCH_OVERRIDE { if( currentGroupInfo.used ) { printSummaryDivider(); stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n"; @@ -8536,7 +9309,7 @@ namespace Catch { } StreamingReporterBase::testGroupEnded( _testGroupStats ); } - virtual void testRunEnded( TestRunStats const& _testRunStats ) { + virtual void testRunEnded( TestRunStats const& _testRunStats ) CATCH_OVERRIDE { printTotalsDivider( _testRunStats.totals ); printTotals( _testRunStats.totals ); stream << std::endl; @@ -8700,12 +9473,7 @@ namespace Catch { stream << "\n" << getLineOfChars<'~'>() << "\n"; Colour colour( Colour::SecondaryText ); stream << currentTestRunInfo->name - << " is a Catch v" << libraryVersion.majorVersion << "." - << libraryVersion.minorVersion << " b" - << libraryVersion.buildNumber; - if( libraryVersion.branchName != std::string( "master" ) ) - stream << " (" << libraryVersion.branchName << ")"; - stream << " host application.\n" + << " is a Catch v" << libraryVersion << " host application.\n" << "Run with -? for options\n\n"; if( m_config->rngSeed() != 0 ) @@ -9180,8 +9948,14 @@ namespace Catch { } // end namespace Catch namespace Catch { + // These are all here to avoid warnings about not having any out of line + // virtual methods NonCopyable::~NonCopyable() {} IShared::~IShared() {} + IStream::~IStream() CATCH_NOEXCEPT {} + FileStream::~FileStream() CATCH_NOEXCEPT {} + CoutStream::~CoutStream() CATCH_NOEXCEPT {} + DebugOutStream::~DebugOutStream() CATCH_NOEXCEPT {} StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {} IContext::~IContext() {} IResultCapture::~IResultCapture() {} @@ -9215,6 +9989,7 @@ namespace Catch { FreeFunctionTestCase::~FreeFunctionTestCase() {} IGeneratorInfo::~IGeneratorInfo() {} IGeneratorsForTest::~IGeneratorsForTest() {} + WildcardPattern::~WildcardPattern() {} TestSpec::Pattern::~Pattern() {} TestSpec::NamePattern::~NamePattern() {} TestSpec::TagPattern::~TagPattern() {} @@ -9226,6 +10001,13 @@ namespace Catch { Matchers::Impl::StdString::EndsWith::~EndsWith() {} void Config::dummy() {} + + namespace TestCaseTracking { + ITracker::~ITracker() {} + TrackerBase::~TrackerBase() {} + SectionTracker::~SectionTracker() {} + IndexTracker::~IndexTracker() {} + } } #ifdef __clang__ @@ -9241,7 +10023,7 @@ namespace Catch { #ifndef __OBJC__ // Standard C/C++ main entry point -int main (int argc, char * const argv[]) { +int main (int argc, char * argv[]) { return Catch::Session().run( argc, argv ); } @@ -9279,8 +10061,9 @@ int main (int argc, char * const argv[]) { #define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" ) #define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" ) -#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" ) +#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "CATCH_REQUIRE_THROWS" ) #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" ) +#define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "CATCH_REQUIRE_THROWS_WITH" ) #define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" ) #define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" ) @@ -9291,6 +10074,7 @@ int main (int argc, char * const argv[]) { #define CATCH_CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" ) #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" ) +#define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CATCH_CHECK_THROWS_WITH" ) #define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" ) @@ -9306,6 +10090,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define CATCH_REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ ) #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ ) @@ -9313,6 +10098,7 @@ int main (int argc, char * const argv[]) { #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define CATCH_REGISTER_TEST_CASE( function, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( function, name, description ) #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg ) #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg ) @@ -9332,11 +10118,11 @@ int main (int argc, char * const argv[]) { #define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags ) #define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define CATCH_GIVEN( desc ) CATCH_SECTION( "Given: " desc, "" ) -#define CATCH_WHEN( desc ) CATCH_SECTION( " When: " desc, "" ) -#define CATCH_AND_WHEN( desc ) CATCH_SECTION( " And: " desc, "" ) -#define CATCH_THEN( desc ) CATCH_SECTION( " Then: " desc, "" ) -#define CATCH_AND_THEN( desc ) CATCH_SECTION( " And: " desc, "" ) +#define CATCH_GIVEN( desc ) CATCH_SECTION( std::string( "Given: ") + desc, "" ) +#define CATCH_WHEN( desc ) CATCH_SECTION( std::string( " When: ") + desc, "" ) +#define CATCH_AND_WHEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) +#define CATCH_THEN( desc ) CATCH_SECTION( std::string( " Then: ") + desc, "" ) +#define CATCH_AND_THEN( desc ) CATCH_SECTION( std::string( " And: ") + desc, "" ) // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required #else @@ -9344,8 +10130,9 @@ int main (int argc, char * const argv[]) { #define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" ) #define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" ) -#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" ) +#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "", "REQUIRE_THROWS" ) #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" ) +#define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, matcher, "REQUIRE_THROWS_WITH" ) #define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" ) #define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" ) @@ -9354,8 +10141,9 @@ int main (int argc, char * const argv[]) { #define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" ) #define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" ) -#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" ) +#define CHECK_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "", "CHECK_THROWS" ) #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" ) +#define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, matcher, "CHECK_THROWS_WITH" ) #define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" ) #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" ) @@ -9371,6 +10159,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ ) #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ ) #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ ) + #define REGISTER_TEST_CASE( ... ) INTERNAL_CATCH_REGISTER_TESTCASE( __VA_ARGS__ ) #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ ) #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ ) #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ ) @@ -9378,6 +10167,7 @@ int main (int argc, char * const argv[]) { #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description ) #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description ) #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description ) + #define REGISTER_TEST_CASE( method, name, description ) INTERNAL_CATCH_REGISTER_TESTCASE( method, name, description ) #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description ) #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg ) #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg ) @@ -9401,27 +10191,13 @@ int main (int argc, char * const argv[]) { #define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags ) #define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags ) #endif -#define GIVEN( desc ) SECTION( " Given: " desc, "" ) -#define WHEN( desc ) SECTION( " When: " desc, "" ) -#define AND_WHEN( desc ) SECTION( "And when: " desc, "" ) -#define THEN( desc ) SECTION( " Then: " desc, "" ) -#define AND_THEN( desc ) SECTION( " And: " desc, "" ) +#define GIVEN( desc ) SECTION( std::string(" Given: ") + desc, "" ) +#define WHEN( desc ) SECTION( std::string(" When: ") + desc, "" ) +#define AND_WHEN( desc ) SECTION( std::string("And when: ") + desc, "" ) +#define THEN( desc ) SECTION( std::string(" Then: ") + desc, "" ) +#define AND_THEN( desc ) SECTION( std::string(" And: ") + desc, "" ) using Catch::Detail::Approx; -// #included from: internal/catch_reenable_warnings.h - -#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED - -#ifdef __clang__ -# ifdef __ICC // icpc defines the __clang__ macro -# pragma warning(pop) -# else -# pragma clang diagnostic pop -# endif -#elif defined __GNUC__ -# pragma GCC diagnostic pop -#endif - #endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED From 1687f6ff1b391f37ee5bc3799e5f2ee2b71f855d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 5 Jan 2016 17:13:36 -0800 Subject: [PATCH 28/37] add custom command line options to unit tests - refs philsquared/Catch#381 --- test/catch.hpp | 2 +- test/unit/run.cpp | 60 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/test/catch.hpp b/test/catch.hpp index 3b759681e..b7ac69633 100644 --- a/test/catch.hpp +++ b/test/catch.hpp @@ -6143,7 +6143,7 @@ namespace Catch { } } - Clara::CommandLine const& cli() const { + Clara::CommandLine & cli() { return m_cli; } std::vector const& unusedTokens() const { diff --git a/test/unit/run.cpp b/test/unit/run.cpp index 8ae4ddc73..caaab46dc 100644 --- a/test/unit/run.cpp +++ b/test/unit/run.cpp @@ -1,17 +1,73 @@ #define CATCH_CONFIG_RUNNER #include "catch.hpp" +#include +#include #include +#include #include "cleanup.hpp" // run_cleanup() +std::string plugin_path; + +inline void set_plugin_path(Catch::ConfigData&, std::string const& _plugin_path ) { + plugin_path = _plugin_path; +} + +std::string working_dir; + +inline void set_working_dir(Catch::ConfigData&, std::string const& _working_dir ) { + working_dir = _working_dir; +} + + int main (int argc, char* const argv[]) { - mapnik::datasource_cache::instance().register_datasources("plugins/input/"); + Catch::Session session; - int result = Catch::Session().run( argc, argv ); + auto & cli = session.cli(); + + cli["-p"]["--plugins"] + .describe("path to mapnik plugins") + .bind(&set_plugin_path, "plugins"); + + cli["-C"]["--working-directory"] + .describe("change working directory") + .bind(&set_working_dir, "working directory"); + + int result = session.applyCommandLine(argc, argv); + + if (!plugin_path.empty()) + { + if (!mapnik::util::exists(plugin_path)) + { + std::clog << "Could not find " << plugin_path << "\n"; + return -1; + } + mapnik::datasource_cache::instance().register_datasources(plugin_path); + } + else + { + mapnik::datasource_cache::instance().register_datasources("plugins/input/"); + } + + if (!working_dir.empty()) + { + if (!mapnik::util::exists(working_dir)) + { + std::clog << "Could not find " << working_dir << "\n"; + return -1; + } + boost::filesystem::current_path(working_dir); + } + + if (result == 0) + { + result = session.run(); + } testing::run_cleanup(); return result; + } From 50905c3f9aad334fd60a5ba41fe7b569979f1b7e Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 6 Jan 2016 12:23:23 +0000 Subject: [PATCH 29/37] c++ style pedantic --- include/mapnik/expression_evaluator.hpp | 8 ++++---- include/mapnik/geometry_reprojection_impl.hpp | 9 +++++---- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index 6ac0451ef..2c1ab1464 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -90,16 +90,16 @@ struct evaluate return geom.value(feature_); } - value_type operator() (binary_node const & x) const + value_type operator() (binary_node const& x) const { return (util::apply_visitor(*this, x.left).to_bool()) && (util::apply_visitor(*this, x.right).to_bool()); } - value_type operator() (binary_node const & x) const + value_type operator() (binary_node const& x) const { - return (util::apply_visitor(*this,x.left).to_bool()) - || (util::apply_visitor(*this,x.right).to_bool()); + return (util::apply_visitor(*this, x.left).to_bool()) + || (util::apply_visitor(*this, x.right).to_bool()); } template diff --git a/include/mapnik/geometry_reprojection_impl.hpp b/include/mapnik/geometry_reprojection_impl.hpp index 7e78635e4..867c0ba44 100644 --- a/include/mapnik/geometry_reprojection_impl.hpp +++ b/include/mapnik/geometry_reprojection_impl.hpp @@ -36,7 +36,7 @@ geometry_empty reproject_internal(geometry_empty const&, proj_transform const&, } template -point reproject_internal(point const & p, proj_transform const& proj_trans, unsigned int & n_err) +point reproject_internal(point const& p, proj_transform const& proj_trans, unsigned int & n_err) { point new_p(p); if (!proj_trans.forward(new_p)) @@ -47,7 +47,7 @@ point reproject_internal(point const & p, proj_transform const& proj_trans } template -line_string reproject_internal(line_string const & ls, proj_transform const& proj_trans, unsigned int & n_err) +line_string reproject_internal(line_string const& ls, proj_transform const& proj_trans, unsigned int & n_err) { line_string new_ls(ls); unsigned int err = proj_trans.forward(new_ls); @@ -59,7 +59,7 @@ line_string reproject_internal(line_string const & ls, proj_transform cons } template -polygon reproject_internal(polygon const & poly, proj_transform const& proj_trans, unsigned int & n_err) +polygon reproject_internal(polygon const& poly, proj_transform const& proj_trans, unsigned int & n_err) { polygon new_poly; linear_ring new_ext(poly.exterior_ring); @@ -171,7 +171,8 @@ geometry_collection reproject_internal(geometry_collection const & c, proj } template -struct geom_reproj_copy_visitor { +struct geom_reproj_copy_visitor +{ geom_reproj_copy_visitor(proj_transform const & proj_trans, unsigned int & n_err) : proj_trans_(proj_trans), From e296e554a89b6cbe19d7b95aa3b0a82c4600d07f Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 6 Jan 2016 12:24:24 +0000 Subject: [PATCH 30/37] sync with https://github.com/mapbox/variant/commit/3ac6e46d01f3a8fbf9944e19d806bc3d456d1a0c --- include/mapnik/util/variant.hpp | 52 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/mapnik/util/variant.hpp b/include/mapnik/util/variant.hpp index 65eb34f35..7ddccefd7 100644 --- a/include/mapnik/util/variant.hpp +++ b/include/mapnik/util/variant.hpp @@ -283,29 +283,20 @@ namespace detail { template struct unwrapper { - T const& operator() (T const& obj) const - { - return obj; - } - - T& operator() (T & obj) const - { - return obj; - } + static T const& apply_const(T const& obj) {return obj;} + static T& apply(T & obj) {return obj;} }; - template struct unwrapper> { - auto operator() (recursive_wrapper const& obj) const + static auto apply_const(recursive_wrapper const& obj) -> typename recursive_wrapper::type const& { return obj.get(); } - - auto operator() (recursive_wrapper & obj) const - -> typename recursive_wrapper::type & + static auto apply(recursive_wrapper & obj) + -> typename recursive_wrapper::type& { return obj.get(); } @@ -314,8 +305,13 @@ struct unwrapper> template struct unwrapper> { - auto operator() (std::reference_wrapper const& obj) const - -> typename recursive_wrapper::type const& + static auto apply_const(std::reference_wrapper const& obj) + -> typename std::reference_wrapper::type const& + { + return obj.get(); + } + static auto apply(std::reference_wrapper & obj) + -> typename std::reference_wrapper::type& { return obj.get(); } @@ -332,7 +328,7 @@ struct dispatcher { if (v.get_type_index() == sizeof...(Types)) { - return f(unwrapper()(v. template get())); + return f(unwrapper::apply_const(v. template get())); } else { @@ -344,7 +340,7 @@ struct dispatcher { if (v.get_type_index() == sizeof...(Types)) { - return f(unwrapper()(v. template get())); + return f(unwrapper::apply(v. template get())); } else { @@ -380,8 +376,8 @@ struct binary_dispatcher_rhs { if (rhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(unwrapper()(lhs. template get()), - unwrapper()(rhs. template get())); + return f(unwrapper::apply_const(lhs. template get()), + unwrapper::apply_const(rhs. template get())); } else { @@ -393,8 +389,8 @@ struct binary_dispatcher_rhs { if (rhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(unwrapper()(lhs. template get()), - unwrapper()(rhs. template get())); + return f(unwrapper::apply(lhs. template get()), + unwrapper::apply(rhs. template get())); } else { @@ -430,7 +426,8 @@ struct binary_dispatcher_lhs { if (lhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(lhs. template get(), rhs. template get()); + return f(unwrapper::apply_const(lhs. template get()), + unwrapper::apply_const(rhs. template get())); } else { @@ -442,7 +439,8 @@ struct binary_dispatcher_lhs { if (lhs.get_type_index() == sizeof...(Types)) // call binary functor { - return f(lhs. template get(), rhs. template get()); + return f(unwrapper::apply(lhs. template get()), + unwrapper::apply(rhs. template get())); } else { @@ -480,7 +478,8 @@ struct binary_dispatcher { if (v0.get_type_index() == v1.get_type_index()) { - return f(v0. template get(), v1. template get()); // call binary functor + return f(unwrapper::apply_const(v0. template get()), + unwrapper::apply_const(v1. template get())); // call binary functor } else { @@ -500,7 +499,8 @@ struct binary_dispatcher { if (v0.get_type_index() == v1.get_type_index()) { - return f(v0. template get(), v1. template get()); // call binary functor + return f(unwrapper::apply(v0. template get()), + unwrapper::apply(v1. template get())); // call binary functor } else { From bb8cd1075114f499bfa8267f8e6c8c9924468388 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 6 Jan 2016 09:16:56 -0800 Subject: [PATCH 31/37] tiff reader: read_generic is not implemented so throw in all cases not just if we can open the image --- src/tiff_reader.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/tiff_reader.cpp b/src/tiff_reader.cpp index 37e59b556..1f885407e 100644 --- a/src/tiff_reader.cpp +++ b/src/tiff_reader.cpp @@ -598,13 +598,9 @@ image_any tiff_reader::read(unsigned x, unsigned y, unsigned width, unsigned } template -void tiff_reader::read_generic(std::size_t, std::size_t, image_rgba8& image) +void tiff_reader::read_generic(std::size_t, std::size_t, image_rgba8&) { - TIFF* tif = open(stream_); - if (tif) - { - throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled"); - } + throw std::runtime_error("tiff_reader: TODO - tiff is not stripped or tiled"); } template From ca83ca167d2b0398a1bc94f6abd9b649f54f3242 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 7 Jan 2016 10:33:57 +0000 Subject: [PATCH 32/37] svg - move stroke-dasharray setup into dash-array parser method --- include/mapnik/svg/svg_path_attributes.hpp | 3 +- include/mapnik/svg/svg_renderer_agg.hpp | 46 +++++++++++----------- include/mapnik/symbolizer.hpp | 6 +-- include/mapnik/symbolizer_utils.hpp | 3 +- include/mapnik/util/dasharray_parser.hpp | 23 +---------- src/dasharray_parser.cpp | 33 +++++++++++++--- 6 files changed, 56 insertions(+), 58 deletions(-) diff --git a/include/mapnik/svg/svg_path_attributes.hpp b/include/mapnik/svg/svg_path_attributes.hpp index 7e180fdce..57544ac21 100644 --- a/include/mapnik/svg/svg_path_attributes.hpp +++ b/include/mapnik/svg/svg_path_attributes.hpp @@ -79,8 +79,7 @@ struct path_attributes even_odd_flag(false), visibility_flag(true), display_flag(true) - { - } + {} // Copy constructor path_attributes(path_attributes const& attr) diff --git a/include/mapnik/svg/svg_renderer_agg.hpp b/include/mapnik/svg/svg_renderer_agg.hpp index ad574cc62..b7d41f5bd 100644 --- a/include/mapnik/svg/svg_renderer_agg.hpp +++ b/include/mapnik/svg/svg_renderer_agg.hpp @@ -60,12 +60,10 @@ namespace mapnik { namespace svg { +// Arbitrary linear gradient specified by two control points. Gradient +// value is taken as the normalised distance along the line segment +// represented by the two points. -/** - * Arbitrary linear gradient specified by two control points. Gradient - * value is taken as the normalised distance along the line segment - * represented by the two points. - */ class linear_gradient_from_segment { public: @@ -105,14 +103,14 @@ template ; - using curved_stroked_type = agg::conv_stroke ; + using curved_type = agg::conv_curve; + using curved_stroked_type = agg::conv_stroke; using curved_stroked_trans_type = agg::conv_transform; - using curved_trans_type = agg::conv_transform ; - using curved_trans_contour_type = agg::conv_contour ; - using renderer_base = agg::renderer_base ; - using vertex_source_type = VertexSource ; - using attribute_source_type = AttributeSource ; + using curved_trans_type = agg::conv_transform; + using curved_trans_contour_type = agg::conv_contour; + using renderer_base = agg::renderer_base; + using vertex_source_type = VertexSource; + using attribute_source_type = AttributeSource; svg_renderer_agg(VertexSource & source, AttributeSource const& attributes) : source_(source), @@ -191,11 +189,11 @@ public: // scale everything up since agg turns things into integers a bit too soon int scaleup=255; - radius*=scaleup; - x1*=scaleup; - y1*=scaleup; - x2*=scaleup; - y2*=scaleup; + radius *= scaleup; + x1 *= scaleup; + y1 *= scaleup; + x2 *= scaleup; + y2 *= scaleup; transform.scale(scaleup,scaleup); interpolator_type span_interpolator(transform); @@ -217,10 +215,10 @@ public: color_func_type>; // scale everything up since agg turns things into integers a bit too soon int scaleup=255; - x1*=scaleup; - y1*=scaleup; - x2*=scaleup; - y2*=scaleup; + x1 *= scaleup; + y1 *= scaleup; + x2 *= scaleup; + y2 *= scaleup; transform.scale(scaleup,scaleup); @@ -288,7 +286,8 @@ public: if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.fill_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + render_gradient(ras, sl, ren, attr.fill_gradient, transform, + attr.fill_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); } else { @@ -324,7 +323,8 @@ public: if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.stroke_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); + render_gradient(ras, sl, ren, attr.stroke_gradient, transform, + attr.stroke_opacity * attr.opacity * opacity, symbol_bbox, curved_trans, attr.index); } else { diff --git a/include/mapnik/symbolizer.hpp b/include/mapnik/symbolizer.hpp index 40283b9d3..39d650d32 100644 --- a/include/mapnik/symbolizer.hpp +++ b/include/mapnik/symbolizer.hpp @@ -317,12 +317,8 @@ struct evaluate_expression_wrapper mapnik::value_type val = util::apply_visitor(mapnik::evaluate(feature,vars), expr); if (val.is_null()) return dash_array(); dash_array dash; - std::vector buf; std::string str = val.to_string(); - if (util::parse_dasharray(str,buf)) - { - util::add_dashes(buf,dash); - } + util::parse_dasharray(str,dash); return dash; } }; diff --git a/include/mapnik/symbolizer_utils.hpp b/include/mapnik/symbolizer_utils.hpp index 358628bd2..cea99000c 100644 --- a/include/mapnik/symbolizer_utils.hpp +++ b/include/mapnik/symbolizer_utils.hpp @@ -404,9 +404,8 @@ struct set_symbolizer_property_impl boost::optional str = node.get_opt_attr(name); if (str) { - std::vector buf; dash_array dash; - if (util::parse_dasharray(*str,buf) && util::add_dashes(buf,dash)) + if (util::parse_dasharray(*str,dash)) { put(sym,key,dash); } diff --git a/include/mapnik/util/dasharray_parser.hpp b/include/mapnik/util/dasharray_parser.hpp index 0ef1ae887..7c5d26711 100644 --- a/include/mapnik/util/dasharray_parser.hpp +++ b/include/mapnik/util/dasharray_parser.hpp @@ -23,32 +23,13 @@ #ifndef MAPNIK_UTIL_DASHARRAY_PARSER_HPP #define MAPNIK_UTIL_DASHARRAY_PARSER_HPP +#include #include #include namespace mapnik { namespace util { -bool parse_dasharray(std::string const& value, std::vector& dasharray); - -inline bool add_dashes(std::vector & buf, std::vector > & dash) -{ - if (buf.empty()) return false; - size_t size = buf.size(); - if (size % 2 == 1) - { - buf.insert(buf.end(),buf.begin(),buf.end()); - } - std::vector::const_iterator pos = buf.begin(); - while (pos != buf.end()) - { - if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0 - { - dash.emplace_back(*pos,*(pos + 1)); - } - pos +=2; - } - return !buf.empty(); -} +bool parse_dasharray(std::string const& value, dash_array & dash); }} diff --git a/src/dasharray_parser.cpp b/src/dasharray_parser.cpp index 760caea25..963a2905a 100644 --- a/src/dasharray_parser.cpp +++ b/src/dasharray_parser.cpp @@ -36,7 +36,29 @@ namespace mapnik { namespace util { -bool parse_dasharray(std::string const& value, std::vector& dasharray) +namespace { +inline bool setup_dashes(std::vector & buf, dash_array & dash) +{ + if (buf.empty()) return false; + size_t size = buf.size(); + if (size % 2 == 1) + { + buf.insert(buf.end(),buf.begin(),buf.end()); + } + std::vector::const_iterator pos = buf.begin(); + while (pos != buf.end()) + { + if (*pos > 0.0 || *(pos+1) > 0.0) // avoid both dash and gap eq 0.0 + { + dash.emplace_back(*pos,*(pos + 1)); + } + pos +=2; + } + return !buf.empty(); +} +} + +bool parse_dasharray(std::string const& value, dash_array & dash) { using namespace boost::spirit; qi::double_type double_; @@ -49,18 +71,19 @@ bool parse_dasharray(std::string const& value, std::vector& dasharray) // dasharray ::= (length | percentage) (comma-wsp dasharray)? // no support for 'percentage' as viewport is unknown at load_map // + std::vector buf; auto first = value.begin(); auto last = value.end(); bool r = qi::phrase_parse(first, last, - (double_[boost::phoenix::push_back(boost::phoenix::ref(dasharray), _1)] % + (double_[boost::phoenix::push_back(boost::phoenix::ref(buf), _1)] % no_skip[char_(", ")] | lit("none")), space); - if (first != last) + if (r && first == last) { - return false; + return setup_dashes(buf, dash); } - return r; + return false; } } // end namespace util From 479a657437e0b72d55d4f453ba8f6f855819b10a Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 8 Jan 2016 11:59:59 +0000 Subject: [PATCH 33/37] make SVG path parser stricter by failing if not all input parsed ref #3225 --- src/svg/svg_path_parser.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/svg/svg_path_parser.cpp b/src/svg/svg_path_parser.cpp index ba0ce07aa..2385c4c36 100644 --- a/src/svg/svg_path_parser.cpp +++ b/src/svg/svg_path_parser.cpp @@ -44,9 +44,9 @@ namespace mapnik { namespace svg { svg_path_grammar g(p); iterator_type first = wkt; iterator_type last = wkt + std::strlen(wkt); - return qi::phrase_parse(first, last, g, skip_type()); + bool status = qi::phrase_parse(first, last, g, skip_type()); + return (status && (first == last)); } - template bool parse_path(const char*, svg_converter_type&); - }} +}} From 9494bc15d4a9d4601174b7b0c9eddd67806027e3 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 8 Jan 2016 12:00:51 +0000 Subject: [PATCH 34/37] SVG path parser - correct handling optional separator (,) between multiple command parts (#3225) http://www.w3.org/TR/SVG/paths.html#PathElement --- include/mapnik/svg/svg_path_grammar.hpp | 35 +++++++------------------ 1 file changed, 9 insertions(+), 26 deletions(-) diff --git a/include/mapnik/svg/svg_path_grammar.hpp b/include/mapnik/svg/svg_path_grammar.hpp index 431bf0aed..93d27f10b 100644 --- a/include/mapnik/svg/svg_path_grammar.hpp +++ b/include/mapnik/svg/svg_path_grammar.hpp @@ -73,46 +73,29 @@ namespace mapnik { namespace svg { >> *(-lit(',') >> coord [ line_to_(_1,_a) ] ); // *line_to H = (lit('H')[_a = false] | lit('h')[_a = true]) - >> +double_[ hline_to_(_1,_a) ] ; // +hline_to + >> (double_[ hline_to_(_1,_a) ] % -lit(',')) ; // +hline_to V = (lit('V')[_a = false] | lit('v')[_a = true]) - >> +double_ [ vline_to_(_1,_a) ]; // +vline_to + >> (double_ [ vline_to_(_1,_a) ] % -lit(',')); // +vline_to L = (lit('L')[_a = false] | lit('l')[_a = true]) - >> +coord [ line_to_(_1,_a) ]; // +line_to + >> (coord [ line_to_(_1,_a) ] % -lit(',')); // +line_to C = (lit('C')[_a = false] | lit('c')[_a = true]) - >> +(coord - >> -lit(',') - >> coord - >> -lit(',') - >> coord) [ curve4_(_1,_2,_3,_a) ]; // +curve4 + >> ((coord >> -lit(',') >> coord >> -lit(',') >> coord) [ curve4_(_1,_2,_3,_a) ] % -lit(',')); // +curve4 S = (lit('S')[_a = false] | lit('s')[_a = true]) - >> +(coord - >> -lit(',') - >> coord) [ curve4_smooth_(_1,_2,_a) ]; // +curve4_smooth (smooth curveto) + >> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto) Q = (lit('Q')[_a = false] | lit('q')[_a = true]) - >> +(coord - >> -lit(',') - >> coord) [ curve3_(_1,_2,_a) ]; // +curve3 (quadratic-bezier-curveto) + >> ((coord >> -lit(',') >> coord) [ curve3_(_1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto) T = (lit('T')[_a = false] | lit('t')[_a = true]) - >> +(coord ) [ curve3_smooth_(_1,_a) ]; // +curve3_smooth (smooth-quadratic-bezier-curveto) + >> ((coord ) [ curve3_smooth_(_1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto) A = (lit('A')[_a = false] | lit('a')[_a = true]) - >> +(coord - >> -lit(',') - >> double_ - >> -lit(',') - >> int_ - >> -lit(',') - >> int_ - >> -lit(',') - >> coord) [arc_to_(_1,_2,_3,_4,_5,_a)]; // arc_to; - - + >> ((coord >> -lit(',') >> double_ >> -lit(',') + >> int_ >> -lit(',') >> int_ >> -lit(',') >> coord) [arc_to_(_1,_2,_3,_4,_5,_a)] % -lit(',')); // arc_to; Z = no_case[lit('z')] [close_()]; // close path From 4e26932868935869b01483a002d054927fe64eef Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 11 Jan 2016 13:48:48 -0800 Subject: [PATCH 35/37] use latest visual test data --- test/data-visual | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data-visual b/test/data-visual index 972b039bf..ccba0eb91 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit 972b039bfc5a5e189f68852c22df717a30c1adf7 +Subproject commit ccba0eb9195bfde35773412b2c4ed92e868e62d7 From 6036711148c76d83d9c24435d77c2fdc58a39d67 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 11 Jan 2016 14:02:57 -0800 Subject: [PATCH 36/37] update to latest visual test images --- test/data-visual | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data-visual b/test/data-visual index ccba0eb91..9841f407a 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit ccba0eb9195bfde35773412b2c4ed92e868e62d7 +Subproject commit 9841f407ac52a9349b632105125e941215336494 From 40fed664df0c7a7133922166e9af1fb6c2feca7f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 11 Jan 2016 14:10:46 -0800 Subject: [PATCH 37/37] more visual test updates --- test/data-visual | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/data-visual b/test/data-visual index 9841f407a..af8869111 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit 9841f407ac52a9349b632105125e941215336494 +Subproject commit af88691110b39c75f97140ab4b608b258e53ad51