aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2024-12-20 12:26:29 +0100
committerBenoit Germain <benoit.germain@ubisoft.com>2024-12-20 12:26:29 +0100
commitfe8d396980f18bf09ee2717817cd795130cf64d1 (patch)
treeada754952fba10d47caab89f57acbe65ab4c7e55
parent48c99e29ae38db79522fb2833f3144ae58c7a906 (diff)
downloadlanes-fe8d396980f18bf09ee2717817cd795130cf64d1.tar.gz
lanes-fe8d396980f18bf09ee2717817cd795130cf64d1.tar.bz2
lanes-fe8d396980f18bf09ee2717817cd795130cf64d1.zip
Migrated unit tests to Catch2 v3.7.1
-rw-r--r--src/deep.cpp8
-rw-r--r--tests/cancel.lua10
-rw-r--r--unit_tests/Catch2.runsettings32
-rw-r--r--unit_tests/UnitTests.vcxproj50
-rw-r--r--unit_tests/UnitTests.vcxproj.filters12
-rw-r--r--unit_tests/UnitTests.vcxproj.user47
-rw-r--r--unit_tests/_pch.cpp13
-rw-r--r--unit_tests/_pch.hpp3
-rw-r--r--unit_tests/catch_amalgamated.cpp11811
-rw-r--r--unit_tests/catch_amalgamated.hpp14106
-rw-r--r--unit_tests/deep_tests.cpp152
-rw-r--r--unit_tests/embedded_tests.cpp192
-rw-r--r--unit_tests/init_and_shutdown.cpp1091
-rw-r--r--unit_tests/lane_tests.cpp426
-rw-r--r--unit_tests/legacy_tests.cpp100
-rw-r--r--unit_tests/linda_tests.cpp586
-rw-r--r--unit_tests/shared.cpp108
-rw-r--r--unit_tests/shared.h38
18 files changed, 27424 insertions, 1361 deletions
diff --git a/src/deep.cpp b/src/deep.cpp
index bc0b73c..c1ef30e 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -112,13 +112,13 @@ int DeepFactory::DeepGC(lua_State* const L_)
112 112
113 if (_isLastRef) { 113 if (_isLastRef) {
114 // retrieve wrapped __gc, if any 114 // retrieve wrapped __gc, if any
115 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: self __gc? 115 lua_pushvalue(L_, lua_upvalueindex(1)); // L_: self __gc?
116 if (!lua_isnil(L_, -1)) { 116 if (!lua_isnil(L_, -1)) {
117 lua_insert(L_, -2); // L_: __gc self 117 lua_insert(L_, -2); // L_: __gc self
118 lua_call(L_, 1, 0); // L_: 118 lua_call(L_, 1, 0); // L_:
119 } else { 119 } else {
120 // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered 120 // need an empty stack in case we are GC_ing from a Keeper, so that empty stack checks aren't triggered
121 lua_pop(L_, 2); // L_: 121 lua_pop(L_, 2); // L_:
122 } 122 }
123 DeleteDeepObject(L_, _p); 123 DeleteDeepObject(L_, _p);
124 } 124 }
diff --git a/tests/cancel.lua b/tests/cancel.lua
index 9b65ad3..84203f1 100644
--- a/tests/cancel.lua
+++ b/tests/cancel.lua
@@ -165,7 +165,7 @@ if not next(which_tests) or which_tests.linda then
165 SLEEP(1) 165 SLEEP(1)
166 166
167 -- linda cancel: linda:receive() returns nil,cancel_error immediately 167 -- linda cancel: linda:receive() returns nil,cancel_error immediately
168 print "cancelling" 168 print "cancelling - both"
169 linda:cancel("both") 169 linda:cancel("both")
170 170
171 -- wait until cancellation is effective. 171 -- wait until cancellation is effective.
@@ -192,7 +192,7 @@ if not next(which_tests) or which_tests.soft then
192 waitCancellation(h, "waiting") 192 waitCancellation(h, "waiting")
193 193
194 -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout. 194 -- soft cancel, this time awakens waiting linda operations, which returns cancel_error immediately, no timeout.
195 print "cancelling" 195 print "cancelling - soft"
196 h:cancel("soft", true) 196 h:cancel("soft", true)
197 197
198 -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message 198 -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message
@@ -209,7 +209,7 @@ if not next(which_tests) or which_tests.hook then
209 SLEEP(2) 209 SLEEP(2)
210 210
211 -- count hook cancel after some instruction instructions 211 -- count hook cancel after some instruction instructions
212 print "cancelling" 212 print "cancelling - line"
213 h:cancel("line", 300, 5.0) 213 h:cancel("line", 300, 5.0)
214 214
215 -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message 215 -- wait until cancellation is effective. the lane will interrupt its loop and print the exit message
@@ -228,7 +228,7 @@ if not next(which_tests) or which_tests.hard then
228 SLEEP(2) 228 SLEEP(2)
229 229
230 -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it 230 -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it
231 print "cancelling" 231 print "cancelling - hard"
232 h:cancel() 232 h:cancel()
233 233
234 -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error 234 -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error
@@ -247,7 +247,7 @@ if not next(which_tests) or which_tests.hard_unprotected then
247 SLEEP(2) 247 SLEEP(2)
248 248
249 -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it 249 -- hard cancel: the lane will be interrupted from inside its current linda:receive() and won't return from it
250 print "cancelling" 250 print "cancelling - hard"
251 h:cancel() 251 h:cancel()
252 252
253 -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error 253 -- wait until cancellation is effective. the lane will be stopped by the linda operation throwing an error
diff --git a/unit_tests/Catch2.runsettings b/unit_tests/Catch2.runsettings
new file mode 100644
index 0000000..9360bfb
--- /dev/null
+++ b/unit_tests/Catch2.runsettings
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="utf-8"?>
2<!-- https://github.com/JohnnyHendriks/TestAdapter_Catch2/blob/main/Docs/Settings.md -->
3<RunSettings>
4 <Catch2Adapter>
5 <DiscoverCommandLine>--list-tests --verbosity high</DiscoverCommandLine>
6 <DiscoverTimeout>300000</DiscoverTimeout>
7
8 <!-- Executable Filename
9 Discover filenames with ... (must not include the .exe extension)
10 Regex breakdown: ^scimitar(_(.+))+(p|r|d)(_?(.+))x*$
11 - ^scimitar : find file that starts with scimitar
12 - (_(.+))+ : follows with a number of elements starting with _ (_foo_bar_dll)
13 - (r|d|p) : contains a word with one of these letters : r (release), d (debug), p (profile).
14 - (_?(.+)): optionally follow with underscores.
15 - x*$ end of line
16 -->
17 <FilenameFilter>UnitTests</FilenameFilter>
18
19 <!-- Enable breaking on failure -->
20 <DebugBreak>on</DebugBreak>
21
22 <!-- Combine: A single test executable is started to run multiple test cases. (Single: instance per test case) -->
23 <ExecutionMode>Combine</ExecutionMode>
24
25 <!-- In Milliseconds -->
26 <TestCaseTimeout>10000</TestCaseTimeout>
27
28 <!-- Working directory -->
29 <WorkingDirectoryRoot>Solution</WorkingDirectoryRoot>
30 <WorkingDirectory>Lanes</WorkingDirectory>
31 </Catch2Adapter>
32</RunSettings> \ No newline at end of file
diff --git a/unit_tests/UnitTests.vcxproj b/unit_tests/UnitTests.vcxproj
index adb90b5..5cc3b2f 100644
--- a/unit_tests/UnitTests.vcxproj
+++ b/unit_tests/UnitTests.vcxproj
@@ -105,7 +105,7 @@
105 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 105 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
106 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 106 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
107 <WarningLevel>Level3</WarningLevel> 107 <WarningLevel>Level3</WarningLevel>
108 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 108 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
109 <LanguageStandard>stdcpp20</LanguageStandard> 109 <LanguageStandard>stdcpp20</LanguageStandard>
110 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 110 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
111 </ClCompile> 111 </ClCompile>
@@ -123,14 +123,14 @@
123 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 123 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
124 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 124 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
125 <WarningLevel>Level3</WarningLevel> 125 <WarningLevel>Level3</WarningLevel>
126 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 126 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua53\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
127 <LanguageStandard>stdcpp20</LanguageStandard> 127 <LanguageStandard>stdcpp20</LanguageStandard>
128 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 128 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
129 </ClCompile> 129 </ClCompile>
130 <Link> 130 <Link>
131 <GenerateDebugInformation>true</GenerateDebugInformation> 131 <GenerateDebugInformation>true</GenerateDebugInformation>
132 <SubSystem>Console</SubSystem> 132 <SubSystem>Console</SubSystem>
133 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 133 <AdditionalDependencies>lua53.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
134 </Link> 134 </Link>
135 </ItemDefinitionGroup> 135 </ItemDefinitionGroup>
136 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'"> 136 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">
@@ -141,14 +141,14 @@
141 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 141 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
142 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 142 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
143 <WarningLevel>Level3</WarningLevel> 143 <WarningLevel>Level3</WarningLevel>
144 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua52\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 144 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua52\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
145 <LanguageStandard>stdcpp20</LanguageStandard> 145 <LanguageStandard>stdcpp20</LanguageStandard>
146 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 146 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
147 </ClCompile> 147 </ClCompile>
148 <Link> 148 <Link>
149 <GenerateDebugInformation>true</GenerateDebugInformation> 149 <GenerateDebugInformation>true</GenerateDebugInformation>
150 <SubSystem>Console</SubSystem> 150 <SubSystem>Console</SubSystem>
151 <AdditionalDependencies>lua52.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 151 <AdditionalDependencies>lua52.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
152 </Link> 152 </Link>
153 </ItemDefinitionGroup> 153 </ItemDefinitionGroup>
154 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'"> 154 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">
@@ -159,14 +159,14 @@
159 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 159 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
160 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 160 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
161 <WarningLevel>Level3</WarningLevel> 161 <WarningLevel>Level3</WarningLevel>
162 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua51\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 162 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua51\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
163 <LanguageStandard>stdcpp20</LanguageStandard> 163 <LanguageStandard>stdcpp20</LanguageStandard>
164 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 164 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
165 </ClCompile> 165 </ClCompile>
166 <Link> 166 <Link>
167 <GenerateDebugInformation>true</GenerateDebugInformation> 167 <GenerateDebugInformation>true</GenerateDebugInformation>
168 <SubSystem>Console</SubSystem> 168 <SubSystem>Console</SubSystem>
169 <AdditionalDependencies>lua51.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 169 <AdditionalDependencies>lua51.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
170 </Link> 170 </Link>
171 </ItemDefinitionGroup> 171 </ItemDefinitionGroup>
172 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 172 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
@@ -177,7 +177,7 @@
177 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 177 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
178 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 178 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
179 <WarningLevel>Level3</WarningLevel> 179 <WarningLevel>Level3</WarningLevel>
180 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 180 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
181 <LanguageStandard>stdcpp20</LanguageStandard> 181 <LanguageStandard>stdcpp20</LanguageStandard>
182 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 182 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
183 </ClCompile> 183 </ClCompile>
@@ -185,7 +185,7 @@
185 <GenerateDebugInformation>true</GenerateDebugInformation> 185 <GenerateDebugInformation>true</GenerateDebugInformation>
186 <SubSystem>Console</SubSystem> 186 <SubSystem>Console</SubSystem>
187 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua54\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories> 187 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua54\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories>
188 <AdditionalDependencies>lua54.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 188 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
189 <IgnoreSpecificDefaultLibraries> 189 <IgnoreSpecificDefaultLibraries>
190 </IgnoreSpecificDefaultLibraries> 190 </IgnoreSpecificDefaultLibraries>
191 </Link> 191 </Link>
@@ -198,7 +198,7 @@
198 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 198 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
199 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 199 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
200 <WarningLevel>Level3</WarningLevel> 200 <WarningLevel>Level3</WarningLevel>
201 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua53\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 201 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua53\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
202 <LanguageStandard>stdcpp20</LanguageStandard> 202 <LanguageStandard>stdcpp20</LanguageStandard>
203 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 203 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
204 </ClCompile> 204 </ClCompile>
@@ -206,7 +206,7 @@
206 <GenerateDebugInformation>true</GenerateDebugInformation> 206 <GenerateDebugInformation>true</GenerateDebugInformation>
207 <SubSystem>Console</SubSystem> 207 <SubSystem>Console</SubSystem>
208 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua53\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories> 208 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua53\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories>
209 <AdditionalDependencies>lua53.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 209 <AdditionalDependencies>lua53.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
210 <IgnoreSpecificDefaultLibraries> 210 <IgnoreSpecificDefaultLibraries>
211 </IgnoreSpecificDefaultLibraries> 211 </IgnoreSpecificDefaultLibraries>
212 </Link> 212 </Link>
@@ -219,7 +219,7 @@
219 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 219 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
220 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 220 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
221 <WarningLevel>Level3</WarningLevel> 221 <WarningLevel>Level3</WarningLevel>
222 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua52\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 222 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua52\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
223 <LanguageStandard>stdcpp20</LanguageStandard> 223 <LanguageStandard>stdcpp20</LanguageStandard>
224 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 224 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
225 </ClCompile> 225 </ClCompile>
@@ -227,7 +227,7 @@
227 <GenerateDebugInformation>true</GenerateDebugInformation> 227 <GenerateDebugInformation>true</GenerateDebugInformation>
228 <SubSystem>Console</SubSystem> 228 <SubSystem>Console</SubSystem>
229 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua52\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories> 229 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua52\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories>
230 <AdditionalDependencies>lua52.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 230 <AdditionalDependencies>lua52.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
231 <IgnoreSpecificDefaultLibraries> 231 <IgnoreSpecificDefaultLibraries>
232 </IgnoreSpecificDefaultLibraries> 232 </IgnoreSpecificDefaultLibraries>
233 </Link> 233 </Link>
@@ -240,7 +240,7 @@
240 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 240 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
241 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 241 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
242 <WarningLevel>Level3</WarningLevel> 242 <WarningLevel>Level3</WarningLevel>
243 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua51\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 243 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua51\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
244 <LanguageStandard>stdcpp20</LanguageStandard> 244 <LanguageStandard>stdcpp20</LanguageStandard>
245 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 245 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
246 </ClCompile> 246 </ClCompile>
@@ -248,7 +248,7 @@
248 <GenerateDebugInformation>true</GenerateDebugInformation> 248 <GenerateDebugInformation>true</GenerateDebugInformation>
249 <SubSystem>Console</SubSystem> 249 <SubSystem>Console</SubSystem>
250 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua51\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories> 250 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua51\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories>
251 <AdditionalDependencies>lua51.lib;gtestd.lib;gtest_maind.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 251 <AdditionalDependencies>lua51.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
252 <IgnoreSpecificDefaultLibraries> 252 <IgnoreSpecificDefaultLibraries>
253 </IgnoreSpecificDefaultLibraries> 253 </IgnoreSpecificDefaultLibraries>
254 </Link> 254 </Link>
@@ -261,7 +261,7 @@
261 <WarningLevel>Level3</WarningLevel> 261 <WarningLevel>Level3</WarningLevel>
262 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 262 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
263 <LanguageStandard>stdcpp20</LanguageStandard> 263 <LanguageStandard>stdcpp20</LanguageStandard>
264 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 264 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
265 </ClCompile> 265 </ClCompile>
266 <Link> 266 <Link>
267 <GenerateDebugInformation>true</GenerateDebugInformation> 267 <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -279,7 +279,7 @@
279 <WarningLevel>Level3</WarningLevel> 279 <WarningLevel>Level3</WarningLevel>
280 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 280 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
281 <LanguageStandard>stdcpp20</LanguageStandard> 281 <LanguageStandard>stdcpp20</LanguageStandard>
282 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\build\native\include\;$(SolutionDir)Lanes</AdditionalIncludeDirectories> 282 <AdditionalIncludeDirectories>$(SolutionDir)..\Lua54\include;$(SolutionDir)Lanes</AdditionalIncludeDirectories>
283 </ClCompile> 283 </ClCompile>
284 <Link> 284 <Link>
285 <GenerateDebugInformation>true</GenerateDebugInformation> 285 <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -287,12 +287,13 @@
287 <OptimizeReferences>true</OptimizeReferences> 287 <OptimizeReferences>true</OptimizeReferences>
288 <EnableCOMDATFolding>true</EnableCOMDATFolding> 288 <EnableCOMDATFolding>true</EnableCOMDATFolding>
289 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua54\bin\$(Platform)\Release;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Release</AdditionalLibraryDirectories> 289 <AdditionalLibraryDirectories>$(SolutionDir)..\Lua54\bin\$(Platform)\Release;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Release</AdditionalLibraryDirectories>
290 <AdditionalDependencies>lua54.lib;gtest.lib;gtest_main.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 290 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
291 </Link> 291 </Link>
292 </ItemDefinitionGroup> 292 </ItemDefinitionGroup>
293 <ItemGroup> 293 <ItemGroup>
294 <ClInclude Include="..\src\compat.hpp" /> 294 <ClInclude Include="..\src\compat.hpp" />
295 <ClInclude Include="..\src\deep.hpp" /> 295 <ClInclude Include="..\src\deep.hpp" />
296 <ClInclude Include="catch_amalgamated.hpp" />
296 <ClInclude Include="_pch.hpp" /> 297 <ClInclude Include="_pch.hpp" />
297 <ClInclude Include="shared.h" /> 298 <ClInclude Include="shared.h" />
298 </ItemGroup> 299 </ItemGroup>
@@ -310,6 +311,18 @@
310 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader> 311 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader>
311 </ClCompile> 312 </ClCompile>
312 <ClCompile Include="..\src\deep.cpp" /> 313 <ClCompile Include="..\src\deep.cpp" />
314 <ClCompile Include="catch_amalgamated.cpp">
315 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">NotUsing</PrecompiledHeader>
316 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">NotUsing</PrecompiledHeader>
317 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">NotUsing</PrecompiledHeader>
318 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">NotUsing</PrecompiledHeader>
319 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">NotUsing</PrecompiledHeader>
320 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">NotUsing</PrecompiledHeader>
321 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">NotUsing</PrecompiledHeader>
322 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">NotUsing</PrecompiledHeader>
323 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">NotUsing</PrecompiledHeader>
324 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader>
325 </ClCompile>
313 <ClCompile Include="deep_tests.cpp" /> 326 <ClCompile Include="deep_tests.cpp" />
314 <ClCompile Include="embedded_tests.cpp" /> 327 <ClCompile Include="embedded_tests.cpp" />
315 <ClCompile Include="lane_tests.cpp" /> 328 <ClCompile Include="lane_tests.cpp" />
@@ -331,6 +344,7 @@
331 </ClCompile> 344 </ClCompile>
332 </ItemGroup> 345 </ItemGroup>
333 <ItemGroup> 346 <ItemGroup>
347 <None Include="Catch2.runsettings" />
334 <None Include="scripts\coro\basics.lua" /> 348 <None Include="scripts\coro\basics.lua" />
335 <None Include="scripts\coro\error_handling.lua" /> 349 <None Include="scripts\coro\error_handling.lua" />
336 <None Include="scripts\lane\cooperative_shutdown.lua" /> 350 <None Include="scripts\lane\cooperative_shutdown.lua" />
diff --git a/unit_tests/UnitTests.vcxproj.filters b/unit_tests/UnitTests.vcxproj.filters
index 64c2a73..45ae229 100644
--- a/unit_tests/UnitTests.vcxproj.filters
+++ b/unit_tests/UnitTests.vcxproj.filters
@@ -15,6 +15,9 @@
15 <ClCompile Include="..\src\deep.cpp"> 15 <ClCompile Include="..\src\deep.cpp">
16 <Filter>Lanes</Filter> 16 <Filter>Lanes</Filter>
17 </ClCompile> 17 </ClCompile>
18 <ClCompile Include="catch_amalgamated.cpp">
19 <Filter>Catch2</Filter>
20 </ClCompile>
18 </ItemGroup> 21 </ItemGroup>
19 <ItemGroup> 22 <ItemGroup>
20 <ClInclude Include="_pch.hpp" /> 23 <ClInclude Include="_pch.hpp" />
@@ -25,6 +28,9 @@
25 <ClInclude Include="..\src\compat.hpp"> 28 <ClInclude Include="..\src\compat.hpp">
26 <Filter>Lanes</Filter> 29 <Filter>Lanes</Filter>
27 </ClInclude> 30 </ClInclude>
31 <ClInclude Include="catch_amalgamated.hpp">
32 <Filter>Catch2</Filter>
33 </ClInclude>
28 </ItemGroup> 34 </ItemGroup>
29 <ItemGroup> 35 <ItemGroup>
30 <Filter Include="Scripts"> 36 <Filter Include="Scripts">
@@ -42,6 +48,9 @@
42 <Filter Include="Scripts\coro"> 48 <Filter Include="Scripts\coro">
43 <UniqueIdentifier>{3cf4f618-1863-4de0-8761-5fca21e6b07c}</UniqueIdentifier> 49 <UniqueIdentifier>{3cf4f618-1863-4de0-8761-5fca21e6b07c}</UniqueIdentifier>
44 </Filter> 50 </Filter>
51 <Filter Include="Catch2">
52 <UniqueIdentifier>{2e1bf85c-7722-42ba-86f8-ac0f5a494ac5}</UniqueIdentifier>
53 </Filter>
45 </ItemGroup> 54 </ItemGroup>
46 <ItemGroup> 55 <ItemGroup>
47 <None Include="scripts\linda\send_receive.lua"> 56 <None Include="scripts\linda\send_receive.lua">
@@ -95,5 +104,8 @@
95 <None Include="scripts\linda\send_registered_userdata.lua"> 104 <None Include="scripts\linda\send_registered_userdata.lua">
96 <Filter>Scripts\linda</Filter> 105 <Filter>Scripts\linda</Filter>
97 </None> 106 </None>
107 <None Include="Catch2.runsettings">
108 <Filter>Catch2</Filter>
109 </None>
98 </ItemGroup> 110 </ItemGroup>
99</Project> \ No newline at end of file 111</Project> \ No newline at end of file
diff --git a/unit_tests/UnitTests.vcxproj.user b/unit_tests/UnitTests.vcxproj.user
new file mode 100644
index 0000000..f9aae23
--- /dev/null
+++ b/unit_tests/UnitTests.vcxproj.user
@@ -0,0 +1,47 @@
1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
4 <LocalDebuggerCommandArguments />
5 <RemoteDebuggerCommandArguments />
6 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
7 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
8 </PropertyGroup>
9 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">
10 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
11 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
12 </PropertyGroup>
13 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">
14 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
15 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
16 </PropertyGroup>
17 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">
18 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
19 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
20 </PropertyGroup>
21 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
22 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
23 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
24 </PropertyGroup>
25 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
26 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
27 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
28 </PropertyGroup>
29 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">
30 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
31 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
32 <LocalDebuggerCommandArguments />
33 <RemoteDebuggerCommandArguments />
34 </PropertyGroup>
35 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">
36 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
37 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
38 </PropertyGroup>
39 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
40 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
41 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
42 </PropertyGroup>
43 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
44 <LocalDebuggerWorkingDirectory>$(SolutionDir)Lanes</LocalDebuggerWorkingDirectory>
45 <DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
46 </PropertyGroup>
47</Project> \ No newline at end of file
diff --git a/unit_tests/_pch.cpp b/unit_tests/_pch.cpp
index 38b27e8..189089a 100644
--- a/unit_tests/_pch.cpp
+++ b/unit_tests/_pch.cpp
@@ -1,4 +1,15 @@
1#include "_pch.hpp" 1#include "_pch.hpp"
2 2
3// IMPORTANT INFORMATION: some relative paths coded in the test implementations suppose that the cwd when debugging is $(SolutionDir)Lanes 3// IMPORTANT INFORMATION: some relative paths coded in the test implementations suppose that the cwd when debugging is $(SolutionDir)Lanes
4// Therefore that's what needs to be set in Google Test Adapter 'Working Directory' global setting... \ No newline at end of file 4// Therefore that's what needs to be set in Google Test Adapter 'Working Directory' global setting...
5
6//int main(int argc, char* argv[])
7//{
8// // your setup ...
9//
10// int result = Catch::Session().run(argc, argv);
11//
12// // your clean-up...
13//
14// return result;
15//} \ No newline at end of file
diff --git a/unit_tests/_pch.hpp b/unit_tests/_pch.hpp
index 5d3c3e9..7fa18a2 100644
--- a/unit_tests/_pch.hpp
+++ b/unit_tests/_pch.hpp
@@ -1,11 +1,12 @@
1#pragma once 1#pragma once
2 2
3#include <cassert>
3#include <filesystem> 4#include <filesystem>
4#include <source_location> 5#include <source_location>
5#include <mutex> 6#include <mutex>
6#include <variant> 7#include <variant>
7 8
8#include "gtest/gtest.h" 9#include "catch_amalgamated.hpp"
9 10
10#ifdef __cplusplus 11#ifdef __cplusplus
11extern "C" 12extern "C"
diff --git a/unit_tests/catch_amalgamated.cpp b/unit_tests/catch_amalgamated.cpp
new file mode 100644
index 0000000..8288905
--- /dev/null
+++ b/unit_tests/catch_amalgamated.cpp
@@ -0,0 +1,11811 @@
1
2// Copyright Catch2 Authors
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE.txt or copy at
5// https://www.boost.org/LICENSE_1_0.txt)
6
7// SPDX-License-Identifier: BSL-1.0
8
9// Catch v3.7.1
10// Generated: 2024-09-17 10:36:45.608896
11// ----------------------------------------------------------
12// This file is an amalgamation of multiple different files.
13// You probably shouldn't edit it directly.
14// ----------------------------------------------------------
15
16#include "catch_amalgamated.hpp"
17
18
19#ifndef CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
20#define CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
21
22
23#if defined(CATCH_PLATFORM_WINDOWS)
24
25// We might end up with the define made globally through the compiler,
26// and we don't want to trigger warnings for this
27#if !defined(NOMINMAX)
28# define NOMINMAX
29#endif
30#if !defined(WIN32_LEAN_AND_MEAN)
31# define WIN32_LEAN_AND_MEAN
32#endif
33
34#include <windows.h>
35
36#endif // defined(CATCH_PLATFORM_WINDOWS)
37
38#endif // CATCH_WINDOWS_H_PROXY_HPP_INCLUDED
39
40
41
42
43namespace Catch {
44 namespace Benchmark {
45 namespace Detail {
46 ChronometerConcept::~ChronometerConcept() = default;
47 } // namespace Detail
48 } // namespace Benchmark
49} // namespace Catch
50
51
52// Adapted from donated nonius code.
53
54
55#include <vector>
56
57namespace Catch {
58 namespace Benchmark {
59 namespace Detail {
60 SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last) {
61 if (!cfg.benchmarkNoAnalysis()) {
62 std::vector<double> samples;
63 samples.reserve(static_cast<size_t>(last - first));
64 for (auto current = first; current != last; ++current) {
65 samples.push_back( current->count() );
66 }
67
68 auto analysis = Catch::Benchmark::Detail::analyse_samples(
69 cfg.benchmarkConfidenceInterval(),
70 cfg.benchmarkResamples(),
71 samples.data(),
72 samples.data() + samples.size() );
73 auto outliers = Catch::Benchmark::Detail::classify_outliers(
74 samples.data(), samples.data() + samples.size() );
75
76 auto wrap_estimate = [](Estimate<double> e) {
77 return Estimate<FDuration> {
78 FDuration(e.point),
79 FDuration(e.lower_bound),
80 FDuration(e.upper_bound),
81 e.confidence_interval,
82 };
83 };
84 std::vector<FDuration> samples2;
85 samples2.reserve(samples.size());
86 for (auto s : samples) {
87 samples2.push_back( FDuration( s ) );
88 }
89
90 return {
91 CATCH_MOVE(samples2),
92 wrap_estimate(analysis.mean),
93 wrap_estimate(analysis.standard_deviation),
94 outliers,
95 analysis.outlier_variance,
96 };
97 } else {
98 std::vector<FDuration> samples;
99 samples.reserve(static_cast<size_t>(last - first));
100
101 FDuration mean = FDuration(0);
102 int i = 0;
103 for (auto it = first; it < last; ++it, ++i) {
104 samples.push_back(*it);
105 mean += *it;
106 }
107 mean /= i;
108
109 return SampleAnalysis{
110 CATCH_MOVE(samples),
111 Estimate<FDuration>{ mean, mean, mean, 0.0 },
112 Estimate<FDuration>{ FDuration( 0 ),
113 FDuration( 0 ),
114 FDuration( 0 ),
115 0.0 },
116 OutlierClassification{},
117 0.0
118 };
119 }
120 }
121 } // namespace Detail
122 } // namespace Benchmark
123} // namespace Catch
124
125
126
127
128namespace Catch {
129 namespace Benchmark {
130 namespace Detail {
131 struct do_nothing {
132 void operator()() const {}
133 };
134
135 BenchmarkFunction::callable::~callable() = default;
136 BenchmarkFunction::BenchmarkFunction():
137 f( new model<do_nothing>{ {} } ){}
138 } // namespace Detail
139 } // namespace Benchmark
140} // namespace Catch
141
142
143
144
145#include <exception>
146
147namespace Catch {
148 namespace Benchmark {
149 namespace Detail {
150 struct optimized_away_error : std::exception {
151 const char* what() const noexcept override;
152 };
153
154 const char* optimized_away_error::what() const noexcept {
155 return "could not measure benchmark, maybe it was optimized away";
156 }
157
158 void throw_optimized_away_error() {
159 Catch::throw_exception(optimized_away_error{});
160 }
161
162 } // namespace Detail
163 } // namespace Benchmark
164} // namespace Catch
165
166
167// Adapted from donated nonius code.
168
169
170
171#include <algorithm>
172#include <cassert>
173#include <cmath>
174#include <cstddef>
175#include <numeric>
176#include <random>
177
178
179#if defined(CATCH_CONFIG_USE_ASYNC)
180#include <future>
181#endif
182
183namespace Catch {
184 namespace Benchmark {
185 namespace Detail {
186 namespace {
187
188 template <typename URng, typename Estimator>
189 static sample
190 resample( URng& rng,
191 unsigned int resamples,
192 double const* first,
193 double const* last,
194 Estimator& estimator ) {
195 auto n = static_cast<size_t>( last - first );
196 Catch::uniform_integer_distribution<size_t> dist( 0, n - 1 );
197
198 sample out;
199 out.reserve( resamples );
200 std::vector<double> resampled;
201 resampled.reserve( n );
202 for ( size_t i = 0; i < resamples; ++i ) {
203 resampled.clear();
204 for ( size_t s = 0; s < n; ++s ) {
205 resampled.push_back( first[dist( rng )] );
206 }
207 const auto estimate =
208 estimator( resampled.data(), resampled.data() + resampled.size() );
209 out.push_back( estimate );
210 }
211 std::sort( out.begin(), out.end() );
212 return out;
213 }
214
215 static double outlier_variance( Estimate<double> mean,
216 Estimate<double> stddev,
217 int n ) {
218 double sb = stddev.point;
219 double mn = mean.point / n;
220 double mg_min = mn / 2.;
221 double sg = (std::min)( mg_min / 4., sb / std::sqrt( n ) );
222 double sg2 = sg * sg;
223 double sb2 = sb * sb;
224
225 auto c_max = [n, mn, sb2, sg2]( double x ) -> double {
226 double k = mn - x;
227 double d = k * k;
228 double nd = n * d;
229 double k0 = -n * nd;
230 double k1 = sb2 - n * sg2 + nd;
231 double det = k1 * k1 - 4 * sg2 * k0;
232 return static_cast<int>( -2. * k0 /
233 ( k1 + std::sqrt( det ) ) );
234 };
235
236 auto var_out = [n, sb2, sg2]( double c ) {
237 double nc = n - c;
238 return ( nc / n ) * ( sb2 - nc * sg2 );
239 };
240
241 return (std::min)( var_out( 1 ),
242 var_out(
243 (std::min)( c_max( 0. ),
244 c_max( mg_min ) ) ) ) /
245 sb2;
246 }
247
248 static double erf_inv( double x ) {
249 // Code accompanying the article "Approximating the erfinv
250 // function" in GPU Computing Gems, Volume 2
251 double w, p;
252
253 w = -log( ( 1.0 - x ) * ( 1.0 + x ) );
254
255 if ( w < 6.250000 ) {
256 w = w - 3.125000;
257 p = -3.6444120640178196996e-21;
258 p = -1.685059138182016589e-19 + p * w;
259 p = 1.2858480715256400167e-18 + p * w;
260 p = 1.115787767802518096e-17 + p * w;
261 p = -1.333171662854620906e-16 + p * w;
262 p = 2.0972767875968561637e-17 + p * w;
263 p = 6.6376381343583238325e-15 + p * w;
264 p = -4.0545662729752068639e-14 + p * w;
265 p = -8.1519341976054721522e-14 + p * w;
266 p = 2.6335093153082322977e-12 + p * w;
267 p = -1.2975133253453532498e-11 + p * w;
268 p = -5.4154120542946279317e-11 + p * w;
269 p = 1.051212273321532285e-09 + p * w;
270 p = -4.1126339803469836976e-09 + p * w;
271 p = -2.9070369957882005086e-08 + p * w;
272 p = 4.2347877827932403518e-07 + p * w;
273 p = -1.3654692000834678645e-06 + p * w;
274 p = -1.3882523362786468719e-05 + p * w;
275 p = 0.0001867342080340571352 + p * w;
276 p = -0.00074070253416626697512 + p * w;
277 p = -0.0060336708714301490533 + p * w;
278 p = 0.24015818242558961693 + p * w;
279 p = 1.6536545626831027356 + p * w;
280 } else if ( w < 16.000000 ) {
281 w = sqrt( w ) - 3.250000;
282 p = 2.2137376921775787049e-09;
283 p = 9.0756561938885390979e-08 + p * w;
284 p = -2.7517406297064545428e-07 + p * w;
285 p = 1.8239629214389227755e-08 + p * w;
286 p = 1.5027403968909827627e-06 + p * w;
287 p = -4.013867526981545969e-06 + p * w;
288 p = 2.9234449089955446044e-06 + p * w;
289 p = 1.2475304481671778723e-05 + p * w;
290 p = -4.7318229009055733981e-05 + p * w;
291 p = 6.8284851459573175448e-05 + p * w;
292 p = 2.4031110387097893999e-05 + p * w;
293 p = -0.0003550375203628474796 + p * w;
294 p = 0.00095328937973738049703 + p * w;
295 p = -0.0016882755560235047313 + p * w;
296 p = 0.0024914420961078508066 + p * w;
297 p = -0.0037512085075692412107 + p * w;
298 p = 0.005370914553590063617 + p * w;
299 p = 1.0052589676941592334 + p * w;
300 p = 3.0838856104922207635 + p * w;
301 } else {
302 w = sqrt( w ) - 5.000000;
303 p = -2.7109920616438573243e-11;
304 p = -2.5556418169965252055e-10 + p * w;
305 p = 1.5076572693500548083e-09 + p * w;
306 p = -3.7894654401267369937e-09 + p * w;
307 p = 7.6157012080783393804e-09 + p * w;
308 p = -1.4960026627149240478e-08 + p * w;
309 p = 2.9147953450901080826e-08 + p * w;
310 p = -6.7711997758452339498e-08 + p * w;
311 p = 2.2900482228026654717e-07 + p * w;
312 p = -9.9298272942317002539e-07 + p * w;
313 p = 4.5260625972231537039e-06 + p * w;
314 p = -1.9681778105531670567e-05 + p * w;
315 p = 7.5995277030017761139e-05 + p * w;
316 p = -0.00021503011930044477347 + p * w;
317 p = -0.00013871931833623122026 + p * w;
318 p = 1.0103004648645343977 + p * w;
319 p = 4.8499064014085844221 + p * w;
320 }
321 return p * x;
322 }
323
324 static double
325 standard_deviation( double const* first, double const* last ) {
326 auto m = Catch::Benchmark::Detail::mean( first, last );
327 double variance =
328 std::accumulate( first,
329 last,
330 0.,
331 [m]( double a, double b ) {
332 double diff = b - m;
333 return a + diff * diff;
334 } ) /
335 ( last - first );
336 return std::sqrt( variance );
337 }
338
339 static sample jackknife( double ( *estimator )( double const*,
340 double const* ),
341 double* first,
342 double* last ) {
343 const auto second = first + 1;
344 sample results;
345 results.reserve( static_cast<size_t>( last - first ) );
346
347 for ( auto it = first; it != last; ++it ) {
348 std::iter_swap( it, first );
349 results.push_back( estimator( second, last ) );
350 }
351
352 return results;
353 }
354
355
356 } // namespace
357 } // namespace Detail
358 } // namespace Benchmark
359} // namespace Catch
360
361namespace Catch {
362 namespace Benchmark {
363 namespace Detail {
364
365 double weighted_average_quantile( int k,
366 int q,
367 double* first,
368 double* last ) {
369 auto count = last - first;
370 double idx = (count - 1) * k / static_cast<double>(q);
371 int j = static_cast<int>(idx);
372 double g = idx - j;
373 std::nth_element(first, first + j, last);
374 auto xj = first[j];
375 if ( Catch::Detail::directCompare( g, 0 ) ) {
376 return xj;
377 }
378
379 auto xj1 = *std::min_element(first + (j + 1), last);
380 return xj + g * (xj1 - xj);
381 }
382
383 OutlierClassification
384 classify_outliers( double const* first, double const* last ) {
385 std::vector<double> copy( first, last );
386
387 auto q1 = weighted_average_quantile( 1, 4, copy.data(), copy.data() + copy.size() );
388 auto q3 = weighted_average_quantile( 3, 4, copy.data(), copy.data() + copy.size() );
389 auto iqr = q3 - q1;
390 auto los = q1 - ( iqr * 3. );
391 auto lom = q1 - ( iqr * 1.5 );
392 auto him = q3 + ( iqr * 1.5 );
393 auto his = q3 + ( iqr * 3. );
394
395 OutlierClassification o;
396 for ( ; first != last; ++first ) {
397 const double t = *first;
398 if ( t < los ) {
399 ++o.low_severe;
400 } else if ( t < lom ) {
401 ++o.low_mild;
402 } else if ( t > his ) {
403 ++o.high_severe;
404 } else if ( t > him ) {
405 ++o.high_mild;
406 }
407 ++o.samples_seen;
408 }
409 return o;
410 }
411
412 double mean( double const* first, double const* last ) {
413 auto count = last - first;
414 double sum = 0.;
415 while (first != last) {
416 sum += *first;
417 ++first;
418 }
419 return sum / static_cast<double>(count);
420 }
421
422 double normal_cdf( double x ) {
423 return std::erfc( -x / std::sqrt( 2.0 ) ) / 2.0;
424 }
425
426 double erfc_inv(double x) {
427 return erf_inv(1.0 - x);
428 }
429
430 double normal_quantile(double p) {
431 static const double ROOT_TWO = std::sqrt(2.0);
432
433 double result = 0.0;
434 assert(p >= 0 && p <= 1);
435 if (p < 0 || p > 1) {
436 return result;
437 }
438
439 result = -erfc_inv(2.0 * p);
440 // result *= normal distribution standard deviation (1.0) * sqrt(2)
441 result *= /*sd * */ ROOT_TWO;
442 // result += normal disttribution mean (0)
443 return result;
444 }
445
446 Estimate<double>
447 bootstrap( double confidence_level,
448 double* first,
449 double* last,
450 sample const& resample,
451 double ( *estimator )( double const*, double const* ) ) {
452 auto n_samples = last - first;
453
454 double point = estimator( first, last );
455 // Degenerate case with a single sample
456 if ( n_samples == 1 )
457 return { point, point, point, confidence_level };
458
459 sample jack = jackknife( estimator, first, last );
460 double jack_mean =
461 mean( jack.data(), jack.data() + jack.size() );
462 double sum_squares = 0, sum_cubes = 0;
463 for ( double x : jack ) {
464 auto difference = jack_mean - x;
465 auto square = difference * difference;
466 auto cube = square * difference;
467 sum_squares += square;
468 sum_cubes += cube;
469 }
470
471 double accel = sum_cubes / ( 6 * std::pow( sum_squares, 1.5 ) );
472 long n = static_cast<long>( resample.size() );
473 double prob_n =
474 std::count_if( resample.begin(),
475 resample.end(),
476 [point]( double x ) { return x < point; } ) /
477 static_cast<double>( n );
478 // degenerate case with uniform samples
479 if ( Catch::Detail::directCompare( prob_n, 0. ) ) {
480 return { point, point, point, confidence_level };
481 }
482
483 double bias = normal_quantile( prob_n );
484 double z1 = normal_quantile( ( 1. - confidence_level ) / 2. );
485
486 auto cumn = [n]( double x ) -> long {
487 return std::lround( normal_cdf( x ) *
488 static_cast<double>( n ) );
489 };
490 auto a = [bias, accel]( double b ) {
491 return bias + b / ( 1. - accel * b );
492 };
493 double b1 = bias + z1;
494 double b2 = bias - z1;
495 double a1 = a( b1 );
496 double a2 = a( b2 );
497 auto lo = static_cast<size_t>( (std::max)( cumn( a1 ), 0l ) );
498 auto hi =
499 static_cast<size_t>( (std::min)( cumn( a2 ), n - 1 ) );
500
501 return { point, resample[lo], resample[hi], confidence_level };
502 }
503
504 bootstrap_analysis analyse_samples(double confidence_level,
505 unsigned int n_resamples,
506 double* first,
507 double* last) {
508 auto mean = &Detail::mean;
509 auto stddev = &standard_deviation;
510
511#if defined(CATCH_CONFIG_USE_ASYNC)
512 auto Estimate = [=](double(*f)(double const*, double const*)) {
513 std::random_device rd;
514 auto seed = rd();
515 return std::async(std::launch::async, [=] {
516 SimplePcg32 rng( seed );
517 auto resampled = resample(rng, n_resamples, first, last, f);
518 return bootstrap(confidence_level, first, last, resampled, f);
519 });
520 };
521
522 auto mean_future = Estimate(mean);
523 auto stddev_future = Estimate(stddev);
524
525 auto mean_estimate = mean_future.get();
526 auto stddev_estimate = stddev_future.get();
527#else
528 auto Estimate = [=](double(*f)(double const* , double const*)) {
529 std::random_device rd;
530 auto seed = rd();
531 SimplePcg32 rng( seed );
532 auto resampled = resample(rng, n_resamples, first, last, f);
533 return bootstrap(confidence_level, first, last, resampled, f);
534 };
535
536 auto mean_estimate = Estimate(mean);
537 auto stddev_estimate = Estimate(stddev);
538#endif // CATCH_USE_ASYNC
539
540 auto n = static_cast<int>(last - first); // seriously, one can't use integral types without hell in C++
541 double outlier_variance = Detail::outlier_variance(mean_estimate, stddev_estimate, n);
542
543 return { mean_estimate, stddev_estimate, outlier_variance };
544 }
545 } // namespace Detail
546 } // namespace Benchmark
547} // namespace Catch
548
549
550
551#include <cmath>
552#include <limits>
553
554namespace {
555
556// Performs equivalent check of std::fabs(lhs - rhs) <= margin
557// But without the subtraction to allow for INFINITY in comparison
558bool marginComparison(double lhs, double rhs, double margin) {
559 return (lhs + margin >= rhs) && (rhs + margin >= lhs);
560}
561
562}
563
564namespace Catch {
565
566 Approx::Approx ( double value )
567 : m_epsilon( static_cast<double>(std::numeric_limits<float>::epsilon())*100. ),
568 m_margin( 0.0 ),
569 m_scale( 0.0 ),
570 m_value( value )
571 {}
572
573 Approx Approx::custom() {
574 return Approx( 0 );
575 }
576
577 Approx Approx::operator-() const {
578 auto temp(*this);
579 temp.m_value = -temp.m_value;
580 return temp;
581 }
582
583
584 std::string Approx::toString() const {
585 ReusableStringStream rss;
586 rss << "Approx( " << ::Catch::Detail::stringify( m_value ) << " )";
587 return rss.str();
588 }
589
590 bool Approx::equalityComparisonImpl(const double other) const {
591 // First try with fixed margin, then compute margin based on epsilon, scale and Approx's value
592 // Thanks to Richard Harris for his help refining the scaled margin value
593 return marginComparison(m_value, other, m_margin)
594 || marginComparison(m_value, other, m_epsilon * (m_scale + std::fabs(std::isinf(m_value)? 0 : m_value)));
595 }
596
597 void Approx::setMargin(double newMargin) {
598 CATCH_ENFORCE(newMargin >= 0,
599 "Invalid Approx::margin: " << newMargin << '.'
600 << " Approx::Margin has to be non-negative.");
601 m_margin = newMargin;
602 }
603
604 void Approx::setEpsilon(double newEpsilon) {
605 CATCH_ENFORCE(newEpsilon >= 0 && newEpsilon <= 1.0,
606 "Invalid Approx::epsilon: " << newEpsilon << '.'
607 << " Approx::epsilon has to be in [0, 1]");
608 m_epsilon = newEpsilon;
609 }
610
611namespace literals {
612 Approx operator ""_a(long double val) {
613 return Approx(val);
614 }
615 Approx operator ""_a(unsigned long long val) {
616 return Approx(val);
617 }
618} // end namespace literals
619
620std::string StringMaker<Catch::Approx>::convert(Catch::Approx const& value) {
621 return value.toString();
622}
623
624} // end namespace Catch
625
626
627
628namespace Catch {
629
630 AssertionResultData::AssertionResultData(ResultWas::OfType _resultType, LazyExpression const& _lazyExpression):
631 lazyExpression(_lazyExpression),
632 resultType(_resultType) {}
633
634 std::string AssertionResultData::reconstructExpression() const {
635
636 if( reconstructedExpression.empty() ) {
637 if( lazyExpression ) {
638 ReusableStringStream rss;
639 rss << lazyExpression;
640 reconstructedExpression = rss.str();
641 }
642 }
643 return reconstructedExpression;
644 }
645
646 AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData&& data )
647 : m_info( info ),
648 m_resultData( CATCH_MOVE(data) )
649 {}
650
651 // Result was a success
652 bool AssertionResult::succeeded() const {
653 return Catch::isOk( m_resultData.resultType );
654 }
655
656 // Result was a success, or failure is suppressed
657 bool AssertionResult::isOk() const {
658 return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
659 }
660
661 ResultWas::OfType AssertionResult::getResultType() const {
662 return m_resultData.resultType;
663 }
664
665 bool AssertionResult::hasExpression() const {
666 return !m_info.capturedExpression.empty();
667 }
668
669 bool AssertionResult::hasMessage() const {
670 return !m_resultData.message.empty();
671 }
672
673 std::string AssertionResult::getExpression() const {
674 // Possibly overallocating by 3 characters should be basically free
675 std::string expr; expr.reserve(m_info.capturedExpression.size() + 3);
676 if (isFalseTest(m_info.resultDisposition)) {
677 expr += "!(";
678 }
679 expr += m_info.capturedExpression;
680 if (isFalseTest(m_info.resultDisposition)) {
681 expr += ')';
682 }
683 return expr;
684 }
685
686 std::string AssertionResult::getExpressionInMacro() const {
687 if ( m_info.macroName.empty() ) {
688 return static_cast<std::string>( m_info.capturedExpression );
689 }
690 std::string expr;
691 expr.reserve( m_info.macroName.size() + m_info.capturedExpression.size() + 4 );
692 expr += m_info.macroName;
693 expr += "( ";
694 expr += m_info.capturedExpression;
695 expr += " )";
696 return expr;
697 }
698
699 bool AssertionResult::hasExpandedExpression() const {
700 return hasExpression() && getExpandedExpression() != getExpression();
701 }
702
703 std::string AssertionResult::getExpandedExpression() const {
704 std::string expr = m_resultData.reconstructExpression();
705 return expr.empty()
706 ? getExpression()
707 : expr;
708 }
709
710 StringRef AssertionResult::getMessage() const {
711 return m_resultData.message;
712 }
713 SourceLineInfo AssertionResult::getSourceInfo() const {
714 return m_info.lineInfo;
715 }
716
717 StringRef AssertionResult::getTestMacroName() const {
718 return m_info.macroName;
719 }
720
721} // end namespace Catch
722
723
724
725#include <fstream>
726
727namespace Catch {
728
729 namespace {
730 static bool enableBazelEnvSupport() {
731#if defined( CATCH_CONFIG_BAZEL_SUPPORT )
732 return true;
733#else
734 return Detail::getEnv( "BAZEL_TEST" ) != nullptr;
735#endif
736 }
737
738 struct bazelShardingOptions {
739 unsigned int shardIndex, shardCount;
740 std::string shardFilePath;
741 };
742
743 static Optional<bazelShardingOptions> readBazelShardingOptions() {
744 const auto bazelShardIndex = Detail::getEnv( "TEST_SHARD_INDEX" );
745 const auto bazelShardTotal = Detail::getEnv( "TEST_TOTAL_SHARDS" );
746 const auto bazelShardInfoFile = Detail::getEnv( "TEST_SHARD_STATUS_FILE" );
747
748
749 const bool has_all =
750 bazelShardIndex && bazelShardTotal && bazelShardInfoFile;
751 if ( !has_all ) {
752 // We provide nice warning message if the input is
753 // misconfigured.
754 auto warn = []( const char* env_var ) {
755 Catch::cerr()
756 << "Warning: Bazel shard configuration is missing '"
757 << env_var << "'. Shard configuration is skipped.\n";
758 };
759 if ( !bazelShardIndex ) {
760 warn( "TEST_SHARD_INDEX" );
761 }
762 if ( !bazelShardTotal ) {
763 warn( "TEST_TOTAL_SHARDS" );
764 }
765 if ( !bazelShardInfoFile ) {
766 warn( "TEST_SHARD_STATUS_FILE" );
767 }
768 return {};
769 }
770
771 auto shardIndex = parseUInt( bazelShardIndex );
772 if ( !shardIndex ) {
773 Catch::cerr()
774 << "Warning: could not parse 'TEST_SHARD_INDEX' ('" << bazelShardIndex
775 << "') as unsigned int.\n";
776 return {};
777 }
778 auto shardTotal = parseUInt( bazelShardTotal );
779 if ( !shardTotal ) {
780 Catch::cerr()
781 << "Warning: could not parse 'TEST_TOTAL_SHARD' ('"
782 << bazelShardTotal << "') as unsigned int.\n";
783 return {};
784 }
785
786 return bazelShardingOptions{
787 *shardIndex, *shardTotal, bazelShardInfoFile };
788
789 }
790 } // end namespace
791
792
793 bool operator==( ProcessedReporterSpec const& lhs,
794 ProcessedReporterSpec const& rhs ) {
795 return lhs.name == rhs.name &&
796 lhs.outputFilename == rhs.outputFilename &&
797 lhs.colourMode == rhs.colourMode &&
798 lhs.customOptions == rhs.customOptions;
799 }
800
801 Config::Config( ConfigData const& data ):
802 m_data( data ) {
803 // We need to trim filter specs to avoid trouble with superfluous
804 // whitespace (esp. important for bdd macros, as those are manually
805 // aligned with whitespace).
806
807 for (auto& elem : m_data.testsOrTags) {
808 elem = trim(elem);
809 }
810 for (auto& elem : m_data.sectionsToRun) {
811 elem = trim(elem);
812 }
813
814 // Insert the default reporter if user hasn't asked for a specific one
815 if ( m_data.reporterSpecifications.empty() ) {
816#if defined( CATCH_CONFIG_DEFAULT_REPORTER )
817 const auto default_spec = CATCH_CONFIG_DEFAULT_REPORTER;
818#else
819 const auto default_spec = "console";
820#endif
821 auto parsed = parseReporterSpec(default_spec);
822 CATCH_ENFORCE( parsed,
823 "Cannot parse the provided default reporter spec: '"
824 << default_spec << '\'' );
825 m_data.reporterSpecifications.push_back( std::move( *parsed ) );
826 }
827
828 if ( enableBazelEnvSupport() ) {
829 readBazelEnvVars();
830 }
831
832 // Bazel support can modify the test specs, so parsing has to happen
833 // after reading Bazel env vars.
834 TestSpecParser parser( ITagAliasRegistry::get() );
835 if ( !m_data.testsOrTags.empty() ) {
836 m_hasTestFilters = true;
837 for ( auto const& testOrTags : m_data.testsOrTags ) {
838 parser.parse( testOrTags );
839 }
840 }
841 m_testSpec = parser.testSpec();
842
843
844 // We now fixup the reporter specs to handle default output spec,
845 // default colour spec, etc
846 bool defaultOutputUsed = false;
847 for ( auto const& reporterSpec : m_data.reporterSpecifications ) {
848 // We do the default-output check separately, while always
849 // using the default output below to make the code simpler
850 // and avoid superfluous copies.
851 if ( reporterSpec.outputFile().none() ) {
852 CATCH_ENFORCE( !defaultOutputUsed,
853 "Internal error: cannot use default output for "
854 "multiple reporters" );
855 defaultOutputUsed = true;
856 }
857
858 m_processedReporterSpecs.push_back( ProcessedReporterSpec{
859 reporterSpec.name(),
860 reporterSpec.outputFile() ? *reporterSpec.outputFile()
861 : data.defaultOutputFilename,
862 reporterSpec.colourMode().valueOr( data.defaultColourMode ),
863 reporterSpec.customOptions() } );
864 }
865 }
866
867 Config::~Config() = default;
868
869
870 bool Config::listTests() const { return m_data.listTests; }
871 bool Config::listTags() const { return m_data.listTags; }
872 bool Config::listReporters() const { return m_data.listReporters; }
873 bool Config::listListeners() const { return m_data.listListeners; }
874
875 std::vector<std::string> const& Config::getTestsOrTags() const { return m_data.testsOrTags; }
876 std::vector<std::string> const& Config::getSectionsToRun() const { return m_data.sectionsToRun; }
877
878 std::vector<ReporterSpec> const& Config::getReporterSpecs() const {
879 return m_data.reporterSpecifications;
880 }
881
882 std::vector<ProcessedReporterSpec> const&
883 Config::getProcessedReporterSpecs() const {
884 return m_processedReporterSpecs;
885 }
886
887 TestSpec const& Config::testSpec() const { return m_testSpec; }
888 bool Config::hasTestFilters() const { return m_hasTestFilters; }
889
890 bool Config::showHelp() const { return m_data.showHelp; }
891
892 // IConfig interface
893 bool Config::allowThrows() const { return !m_data.noThrow; }
894 StringRef Config::name() const { return m_data.name.empty() ? m_data.processName : m_data.name; }
895 bool Config::includeSuccessfulResults() const { return m_data.showSuccessfulTests; }
896 bool Config::warnAboutMissingAssertions() const {
897 return !!( m_data.warnings & WarnAbout::NoAssertions );
898 }
899 bool Config::warnAboutUnmatchedTestSpecs() const {
900 return !!( m_data.warnings & WarnAbout::UnmatchedTestSpec );
901 }
902 bool Config::zeroTestsCountAsSuccess() const { return m_data.allowZeroTests; }
903 ShowDurations Config::showDurations() const { return m_data.showDurations; }
904 double Config::minDuration() const { return m_data.minDuration; }
905 TestRunOrder Config::runOrder() const { return m_data.runOrder; }
906 uint32_t Config::rngSeed() const { return m_data.rngSeed; }
907 unsigned int Config::shardCount() const { return m_data.shardCount; }
908 unsigned int Config::shardIndex() const { return m_data.shardIndex; }
909 ColourMode Config::defaultColourMode() const { return m_data.defaultColourMode; }
910 bool Config::shouldDebugBreak() const { return m_data.shouldDebugBreak; }
911 int Config::abortAfter() const { return m_data.abortAfter; }
912 bool Config::showInvisibles() const { return m_data.showInvisibles; }
913 Verbosity Config::verbosity() const { return m_data.verbosity; }
914
915 bool Config::skipBenchmarks() const { return m_data.skipBenchmarks; }
916 bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; }
917 unsigned int Config::benchmarkSamples() const { return m_data.benchmarkSamples; }
918 double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; }
919 unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; }
920 std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); }
921
922 void Config::readBazelEnvVars() {
923 // Register a JUnit reporter for Bazel. Bazel sets an environment
924 // variable with the path to XML output. If this file is written to
925 // during test, Bazel will not generate a default XML output.
926 // This allows the XML output file to contain higher level of detail
927 // than what is possible otherwise.
928 const auto bazelOutputFile = Detail::getEnv( "XML_OUTPUT_FILE" );
929
930 if ( bazelOutputFile ) {
931 m_data.reporterSpecifications.push_back(
932 { "junit", std::string( bazelOutputFile ), {}, {} } );
933 }
934
935 const auto bazelTestSpec = Detail::getEnv( "TESTBRIDGE_TEST_ONLY" );
936 if ( bazelTestSpec ) {
937 // Presumably the test spec from environment should overwrite
938 // the one we got from CLI (if we got any)
939 m_data.testsOrTags.clear();
940 m_data.testsOrTags.push_back( bazelTestSpec );
941 }
942
943 const auto bazelShardOptions = readBazelShardingOptions();
944 if ( bazelShardOptions ) {
945 std::ofstream f( bazelShardOptions->shardFilePath,
946 std::ios_base::out | std::ios_base::trunc );
947 if ( f.is_open() ) {
948 f << "";
949 m_data.shardIndex = bazelShardOptions->shardIndex;
950 m_data.shardCount = bazelShardOptions->shardCount;
951 }
952 }
953 }
954
955} // end namespace Catch
956
957
958
959
960
961namespace Catch {
962 std::uint32_t getSeed() {
963 return getCurrentContext().getConfig()->rngSeed();
964 }
965}
966
967
968
969#include <cassert>
970#include <stack>
971
972namespace Catch {
973
974 ////////////////////////////////////////////////////////////////////////////
975
976
977 ScopedMessage::ScopedMessage( MessageBuilder&& builder ):
978 m_info( CATCH_MOVE(builder.m_info) ) {
979 m_info.message = builder.m_stream.str();
980 getResultCapture().pushScopedMessage( m_info );
981 }
982
983 ScopedMessage::ScopedMessage( ScopedMessage&& old ) noexcept:
984 m_info( CATCH_MOVE( old.m_info ) ) {
985 old.m_moved = true;
986 }
987
988 ScopedMessage::~ScopedMessage() {
989 if ( !uncaught_exceptions() && !m_moved ){
990 getResultCapture().popScopedMessage(m_info);
991 }
992 }
993
994
995 Capturer::Capturer( StringRef macroName,
996 SourceLineInfo const& lineInfo,
997 ResultWas::OfType resultType,
998 StringRef names ):
999 m_resultCapture( getResultCapture() ) {
1000 auto trimmed = [&] (size_t start, size_t end) {
1001 while (names[start] == ',' || isspace(static_cast<unsigned char>(names[start]))) {
1002 ++start;
1003 }
1004 while (names[end] == ',' || isspace(static_cast<unsigned char>(names[end]))) {
1005 --end;
1006 }
1007 return names.substr(start, end - start + 1);
1008 };
1009 auto skipq = [&] (size_t start, char quote) {
1010 for (auto i = start + 1; i < names.size() ; ++i) {
1011 if (names[i] == quote)
1012 return i;
1013 if (names[i] == '\\')
1014 ++i;
1015 }
1016 CATCH_INTERNAL_ERROR("CAPTURE parsing encountered unmatched quote");
1017 };
1018
1019 size_t start = 0;
1020 std::stack<char> openings;
1021 for (size_t pos = 0; pos < names.size(); ++pos) {
1022 char c = names[pos];
1023 switch (c) {
1024 case '[':
1025 case '{':
1026 case '(':
1027 // It is basically impossible to disambiguate between
1028 // comparison and start of template args in this context
1029// case '<':
1030 openings.push(c);
1031 break;
1032 case ']':
1033 case '}':
1034 case ')':
1035// case '>':
1036 openings.pop();
1037 break;
1038 case '"':
1039 case '\'':
1040 pos = skipq(pos, c);
1041 break;
1042 case ',':
1043 if (start != pos && openings.empty()) {
1044 m_messages.emplace_back(macroName, lineInfo, resultType);
1045 m_messages.back().message = static_cast<std::string>(trimmed(start, pos));
1046 m_messages.back().message += " := ";
1047 start = pos;
1048 }
1049 break;
1050 default:; // noop
1051 }
1052 }
1053 assert(openings.empty() && "Mismatched openings");
1054 m_messages.emplace_back(macroName, lineInfo, resultType);
1055 m_messages.back().message = static_cast<std::string>(trimmed(start, names.size() - 1));
1056 m_messages.back().message += " := ";
1057 }
1058 Capturer::~Capturer() {
1059 if ( !uncaught_exceptions() ){
1060 assert( m_captured == m_messages.size() );
1061 for( size_t i = 0; i < m_captured; ++i )
1062 m_resultCapture.popScopedMessage( m_messages[i] );
1063 }
1064 }
1065
1066 void Capturer::captureValue( size_t index, std::string const& value ) {
1067 assert( index < m_messages.size() );
1068 m_messages[index].message += value;
1069 m_resultCapture.pushScopedMessage( m_messages[index] );
1070 m_captured++;
1071 }
1072
1073} // end namespace Catch
1074
1075
1076
1077
1078#include <exception>
1079
1080namespace Catch {
1081
1082 namespace {
1083
1084 class RegistryHub : public IRegistryHub,
1085 public IMutableRegistryHub,
1086 private Detail::NonCopyable {
1087
1088 public: // IRegistryHub
1089 RegistryHub() = default;
1090 ReporterRegistry const& getReporterRegistry() const override {
1091 return m_reporterRegistry;
1092 }
1093 ITestCaseRegistry const& getTestCaseRegistry() const override {
1094 return m_testCaseRegistry;
1095 }
1096 IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const override {
1097 return m_exceptionTranslatorRegistry;
1098 }
1099 ITagAliasRegistry const& getTagAliasRegistry() const override {
1100 return m_tagAliasRegistry;
1101 }
1102 StartupExceptionRegistry const& getStartupExceptionRegistry() const override {
1103 return m_exceptionRegistry;
1104 }
1105
1106 public: // IMutableRegistryHub
1107 void registerReporter( std::string const& name, IReporterFactoryPtr factory ) override {
1108 m_reporterRegistry.registerReporter( name, CATCH_MOVE(factory) );
1109 }
1110 void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) override {
1111 m_reporterRegistry.registerListener( CATCH_MOVE(factory) );
1112 }
1113 void registerTest( Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker ) override {
1114 m_testCaseRegistry.registerTest( CATCH_MOVE(testInfo), CATCH_MOVE(invoker) );
1115 }
1116 void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) override {
1117 m_exceptionTranslatorRegistry.registerTranslator( CATCH_MOVE(translator) );
1118 }
1119 void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) override {
1120 m_tagAliasRegistry.add( alias, tag, lineInfo );
1121 }
1122 void registerStartupException() noexcept override {
1123#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1124 m_exceptionRegistry.add(std::current_exception());
1125#else
1126 CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
1127#endif
1128 }
1129 IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override {
1130 return m_enumValuesRegistry;
1131 }
1132
1133 private:
1134 TestRegistry m_testCaseRegistry;
1135 ReporterRegistry m_reporterRegistry;
1136 ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
1137 TagAliasRegistry m_tagAliasRegistry;
1138 StartupExceptionRegistry m_exceptionRegistry;
1139 Detail::EnumValuesRegistry m_enumValuesRegistry;
1140 };
1141 }
1142
1143 using RegistryHubSingleton = Singleton<RegistryHub, IRegistryHub, IMutableRegistryHub>;
1144
1145 IRegistryHub const& getRegistryHub() {
1146 return RegistryHubSingleton::get();
1147 }
1148 IMutableRegistryHub& getMutableRegistryHub() {
1149 return RegistryHubSingleton::getMutable();
1150 }
1151 void cleanUp() {
1152 cleanupSingletons();
1153 cleanUpContext();
1154 }
1155 std::string translateActiveException() {
1156 return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
1157 }
1158
1159
1160} // end namespace Catch
1161
1162
1163
1164#include <algorithm>
1165#include <cassert>
1166#include <exception>
1167#include <iomanip>
1168#include <set>
1169
1170namespace Catch {
1171
1172 namespace {
1173 static constexpr int TestFailureExitCode = 42;
1174 static constexpr int UnspecifiedErrorExitCode = 1;
1175 static constexpr int AllTestsSkippedExitCode = 4;
1176 static constexpr int NoTestsRunExitCode = 2;
1177 static constexpr int UnmatchedTestSpecExitCode = 3;
1178 static constexpr int InvalidTestSpecExitCode = 5;
1179
1180
1181 IEventListenerPtr createReporter(std::string const& reporterName, ReporterConfig&& config) {
1182 auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, CATCH_MOVE(config));
1183 CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << '\'');
1184
1185 return reporter;
1186 }
1187
1188 IEventListenerPtr prepareReporters(Config const* config) {
1189 if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()
1190 && config->getProcessedReporterSpecs().size() == 1) {
1191 auto const& spec = config->getProcessedReporterSpecs()[0];
1192 return createReporter(
1193 spec.name,
1194 ReporterConfig( config,
1195 makeStream( spec.outputFilename ),
1196 spec.colourMode,
1197 spec.customOptions ) );
1198 }
1199
1200 auto multi = Detail::make_unique<MultiReporter>(config);
1201
1202 auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
1203 for (auto const& listener : listeners) {
1204 multi->addListener(listener->create(config));
1205 }
1206
1207 for ( auto const& reporterSpec : config->getProcessedReporterSpecs() ) {
1208 multi->addReporter( createReporter(
1209 reporterSpec.name,
1210 ReporterConfig( config,
1211 makeStream( reporterSpec.outputFilename ),
1212 reporterSpec.colourMode,
1213 reporterSpec.customOptions ) ) );
1214 }
1215
1216 return multi;
1217 }
1218
1219 class TestGroup {
1220 public:
1221 explicit TestGroup(IEventListenerPtr&& reporter, Config const* config):
1222 m_reporter(reporter.get()),
1223 m_config{config},
1224 m_context{config, CATCH_MOVE(reporter)} {
1225
1226 assert( m_config->testSpec().getInvalidSpecs().empty() &&
1227 "Invalid test specs should be handled before running tests" );
1228
1229 auto const& allTestCases = getAllTestCasesSorted(*m_config);
1230 auto const& testSpec = m_config->testSpec();
1231 if ( !testSpec.hasFilters() ) {
1232 for ( auto const& test : allTestCases ) {
1233 if ( !test.getTestCaseInfo().isHidden() ) {
1234 m_tests.emplace( &test );
1235 }
1236 }
1237 } else {
1238 m_matches =
1239 testSpec.matchesByFilter( allTestCases, *m_config );
1240 for ( auto const& match : m_matches ) {
1241 m_tests.insert( match.tests.begin(),
1242 match.tests.end() );
1243 }
1244 }
1245
1246 m_tests = createShard(m_tests, m_config->shardCount(), m_config->shardIndex());
1247 }
1248
1249 Totals execute() {
1250 Totals totals;
1251 for (auto const& testCase : m_tests) {
1252 if (!m_context.aborting())
1253 totals += m_context.runTest(*testCase);
1254 else
1255 m_reporter->skipTest(testCase->getTestCaseInfo());
1256 }
1257
1258 for (auto const& match : m_matches) {
1259 if (match.tests.empty()) {
1260 m_unmatchedTestSpecs = true;
1261 m_reporter->noMatchingTestCases( match.name );
1262 }
1263 }
1264
1265 return totals;
1266 }
1267
1268 bool hadUnmatchedTestSpecs() const {
1269 return m_unmatchedTestSpecs;
1270 }
1271
1272
1273 private:
1274 IEventListener* m_reporter;
1275 Config const* m_config;
1276 RunContext m_context;
1277 std::set<TestCaseHandle const*> m_tests;
1278 TestSpec::Matches m_matches;
1279 bool m_unmatchedTestSpecs = false;
1280 };
1281
1282 void applyFilenamesAsTags() {
1283 for (auto const& testInfo : getRegistryHub().getTestCaseRegistry().getAllInfos()) {
1284 testInfo->addFilenameTag();
1285 }
1286 }
1287
1288 } // anon namespace
1289
1290 Session::Session() {
1291 static bool alreadyInstantiated = false;
1292 if( alreadyInstantiated ) {
1293 CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
1294 CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
1295 }
1296
1297 // There cannot be exceptions at startup in no-exception mode.
1298#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1299 const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
1300 if ( !exceptions.empty() ) {
1301 config();
1302 getCurrentMutableContext().setConfig(m_config.get());
1303
1304 m_startupExceptions = true;
1305 auto errStream = makeStream( "%stderr" );
1306 auto colourImpl = makeColourImpl(
1307 ColourMode::PlatformDefault, errStream.get() );
1308 auto guard = colourImpl->guardColour( Colour::Red );
1309 errStream->stream() << "Errors occurred during startup!" << '\n';
1310 // iterate over all exceptions and notify user
1311 for ( const auto& ex_ptr : exceptions ) {
1312 try {
1313 std::rethrow_exception(ex_ptr);
1314 } catch ( std::exception const& ex ) {
1315 errStream->stream() << TextFlow::Column( ex.what() ).indent(2) << '\n';
1316 }
1317 }
1318 }
1319#endif
1320
1321 alreadyInstantiated = true;
1322 m_cli = makeCommandLineParser( m_configData );
1323 }
1324 Session::~Session() {
1325 Catch::cleanUp();
1326 }
1327
1328 void Session::showHelp() const {
1329 Catch::cout()
1330 << "\nCatch2 v" << libraryVersion() << '\n'
1331 << m_cli << '\n'
1332 << "For more detailed usage please see the project docs\n\n" << std::flush;
1333 }
1334 void Session::libIdentify() {
1335 Catch::cout()
1336 << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
1337 << std::left << std::setw(16) << "category: " << "testframework\n"
1338 << std::left << std::setw(16) << "framework: " << "Catch2\n"
1339 << std::left << std::setw(16) << "version: " << libraryVersion() << '\n' << std::flush;
1340 }
1341
1342 int Session::applyCommandLine( int argc, char const * const * argv ) {
1343 if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
1344
1345 auto result = m_cli.parse( Clara::Args( argc, argv ) );
1346
1347 if( !result ) {
1348 config();
1349 getCurrentMutableContext().setConfig(m_config.get());
1350 auto errStream = makeStream( "%stderr" );
1351 auto colour = makeColourImpl( ColourMode::PlatformDefault, errStream.get() );
1352
1353 errStream->stream()
1354 << colour->guardColour( Colour::Red )
1355 << "\nError(s) in input:\n"
1356 << TextFlow::Column( result.errorMessage() ).indent( 2 )
1357 << "\n\n";
1358 errStream->stream() << "Run with -? for usage\n\n" << std::flush;
1359 return UnspecifiedErrorExitCode;
1360 }
1361
1362 if( m_configData.showHelp )
1363 showHelp();
1364 if( m_configData.libIdentify )
1365 libIdentify();
1366
1367 m_config.reset();
1368 return 0;
1369 }
1370
1371#if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
1372 int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
1373
1374 char **utf8Argv = new char *[ argc ];
1375
1376 for ( int i = 0; i < argc; ++i ) {
1377 int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
1378
1379 utf8Argv[ i ] = new char[ bufSize ];
1380
1381 WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
1382 }
1383
1384 int returnCode = applyCommandLine( argc, utf8Argv );
1385
1386 for ( int i = 0; i < argc; ++i )
1387 delete [] utf8Argv[ i ];
1388
1389 delete [] utf8Argv;
1390
1391 return returnCode;
1392 }
1393#endif
1394
1395 void Session::useConfigData( ConfigData const& configData ) {
1396 m_configData = configData;
1397 m_config.reset();
1398 }
1399
1400 int Session::run() {
1401 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
1402 Catch::cout() << "...waiting for enter/ return before starting\n" << std::flush;
1403 static_cast<void>(std::getchar());
1404 }
1405 int exitCode = runInternal();
1406 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
1407 Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << '\n' << std::flush;
1408 static_cast<void>(std::getchar());
1409 }
1410 return exitCode;
1411 }
1412
1413 Clara::Parser const& Session::cli() const {
1414 return m_cli;
1415 }
1416 void Session::cli( Clara::Parser const& newParser ) {
1417 m_cli = newParser;
1418 }
1419 ConfigData& Session::configData() {
1420 return m_configData;
1421 }
1422 Config& Session::config() {
1423 if( !m_config )
1424 m_config = Detail::make_unique<Config>( m_configData );
1425 return *m_config;
1426 }
1427
1428 int Session::runInternal() {
1429 if ( m_startupExceptions ) { return UnspecifiedErrorExitCode; }
1430
1431 if (m_configData.showHelp || m_configData.libIdentify) {
1432 return 0;
1433 }
1434
1435 if ( m_configData.shardIndex >= m_configData.shardCount ) {
1436 Catch::cerr() << "The shard count (" << m_configData.shardCount
1437 << ") must be greater than the shard index ("
1438 << m_configData.shardIndex << ")\n"
1439 << std::flush;
1440 return UnspecifiedErrorExitCode;
1441 }
1442
1443 CATCH_TRY {
1444 config(); // Force config to be constructed
1445
1446 seedRng( *m_config );
1447
1448 if (m_configData.filenamesAsTags) {
1449 applyFilenamesAsTags();
1450 }
1451
1452 // Set up global config instance before we start calling into other functions
1453 getCurrentMutableContext().setConfig(m_config.get());
1454
1455 // Create reporter(s) so we can route listings through them
1456 auto reporter = prepareReporters(m_config.get());
1457
1458 auto const& invalidSpecs = m_config->testSpec().getInvalidSpecs();
1459 if ( !invalidSpecs.empty() ) {
1460 for ( auto const& spec : invalidSpecs ) {
1461 reporter->reportInvalidTestSpec( spec );
1462 }
1463 return InvalidTestSpecExitCode;
1464 }
1465
1466
1467 // Handle list request
1468 if (list(*reporter, *m_config)) {
1469 return 0;
1470 }
1471
1472 TestGroup tests { CATCH_MOVE(reporter), m_config.get() };
1473 auto const totals = tests.execute();
1474
1475 if ( tests.hadUnmatchedTestSpecs()
1476 && m_config->warnAboutUnmatchedTestSpecs() ) {
1477 // UnmatchedTestSpecExitCode
1478 return UnmatchedTestSpecExitCode;
1479 }
1480
1481 if ( totals.testCases.total() == 0
1482 && !m_config->zeroTestsCountAsSuccess() ) {
1483 return NoTestsRunExitCode;
1484 }
1485
1486 if ( totals.testCases.total() > 0 &&
1487 totals.testCases.total() == totals.testCases.skipped
1488 && !m_config->zeroTestsCountAsSuccess() ) {
1489 return AllTestsSkippedExitCode;
1490 }
1491
1492 if ( totals.assertions.failed ) { return TestFailureExitCode; }
1493 return 0;
1494
1495 }
1496#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
1497 catch( std::exception& ex ) {
1498 Catch::cerr() << ex.what() << '\n' << std::flush;
1499 return UnspecifiedErrorExitCode;
1500 }
1501#endif
1502 }
1503
1504} // end namespace Catch
1505
1506
1507
1508
1509namespace Catch {
1510
1511 RegistrarForTagAliases::RegistrarForTagAliases(char const* alias, char const* tag, SourceLineInfo const& lineInfo) {
1512 CATCH_TRY {
1513 getMutableRegistryHub().registerTagAlias(alias, tag, lineInfo);
1514 } CATCH_CATCH_ALL {
1515 // Do not throw when constructing global objects, instead register the exception to be processed later
1516 getMutableRegistryHub().registerStartupException();
1517 }
1518 }
1519
1520}
1521
1522
1523
1524#include <cassert>
1525#include <cctype>
1526#include <algorithm>
1527
1528namespace Catch {
1529
1530 namespace {
1531 using TCP_underlying_type = uint8_t;
1532 static_assert(sizeof(TestCaseProperties) == sizeof(TCP_underlying_type),
1533 "The size of the TestCaseProperties is different from the assumed size");
1534
1535 constexpr TestCaseProperties operator|(TestCaseProperties lhs, TestCaseProperties rhs) {
1536 return static_cast<TestCaseProperties>(
1537 static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1538 );
1539 }
1540
1541 constexpr TestCaseProperties& operator|=(TestCaseProperties& lhs, TestCaseProperties rhs) {
1542 lhs = static_cast<TestCaseProperties>(
1543 static_cast<TCP_underlying_type>(lhs) | static_cast<TCP_underlying_type>(rhs)
1544 );
1545 return lhs;
1546 }
1547
1548 constexpr TestCaseProperties operator&(TestCaseProperties lhs, TestCaseProperties rhs) {
1549 return static_cast<TestCaseProperties>(
1550 static_cast<TCP_underlying_type>(lhs) & static_cast<TCP_underlying_type>(rhs)
1551 );
1552 }
1553
1554 constexpr bool applies(TestCaseProperties tcp) {
1555 static_assert(static_cast<TCP_underlying_type>(TestCaseProperties::None) == 0,
1556 "TestCaseProperties::None must be equal to 0");
1557 return tcp != TestCaseProperties::None;
1558 }
1559
1560 TestCaseProperties parseSpecialTag( StringRef tag ) {
1561 if( !tag.empty() && tag[0] == '.' )
1562 return TestCaseProperties::IsHidden;
1563 else if( tag == "!throws"_sr )
1564 return TestCaseProperties::Throws;
1565 else if( tag == "!shouldfail"_sr )
1566 return TestCaseProperties::ShouldFail;
1567 else if( tag == "!mayfail"_sr )
1568 return TestCaseProperties::MayFail;
1569 else if( tag == "!nonportable"_sr )
1570 return TestCaseProperties::NonPortable;
1571 else if( tag == "!benchmark"_sr )
1572 return TestCaseProperties::Benchmark | TestCaseProperties::IsHidden;
1573 else
1574 return TestCaseProperties::None;
1575 }
1576 bool isReservedTag( StringRef tag ) {
1577 return parseSpecialTag( tag ) == TestCaseProperties::None
1578 && tag.size() > 0
1579 && !std::isalnum( static_cast<unsigned char>(tag[0]) );
1580 }
1581 void enforceNotReservedTag( StringRef tag, SourceLineInfo const& _lineInfo ) {
1582 CATCH_ENFORCE( !isReservedTag(tag),
1583 "Tag name: [" << tag << "] is not allowed.\n"
1584 << "Tag names starting with non alphanumeric characters are reserved\n"
1585 << _lineInfo );
1586 }
1587
1588 std::string makeDefaultName() {
1589 static size_t counter = 0;
1590 return "Anonymous test case " + std::to_string(++counter);
1591 }
1592
1593 constexpr StringRef extractFilenamePart(StringRef filename) {
1594 size_t lastDot = filename.size();
1595 while (lastDot > 0 && filename[lastDot - 1] != '.') {
1596 --lastDot;
1597 }
1598 // In theory we could have filename without any extension in it
1599 if ( lastDot == 0 ) { return StringRef(); }
1600
1601 --lastDot;
1602 size_t nameStart = lastDot;
1603 while (nameStart > 0 && filename[nameStart - 1] != '/' && filename[nameStart - 1] != '\\') {
1604 --nameStart;
1605 }
1606
1607 return filename.substr(nameStart, lastDot - nameStart);
1608 }
1609
1610 // Returns the upper bound on size of extra tags ([#file]+[.])
1611 constexpr size_t sizeOfExtraTags(StringRef filepath) {
1612 // [.] is 3, [#] is another 3
1613 const size_t extras = 3 + 3;
1614 return extractFilenamePart(filepath).size() + extras;
1615 }
1616 } // end unnamed namespace
1617
1618 bool operator<( Tag const& lhs, Tag const& rhs ) {
1619 Detail::CaseInsensitiveLess cmp;
1620 return cmp( lhs.original, rhs.original );
1621 }
1622 bool operator==( Tag const& lhs, Tag const& rhs ) {
1623 Detail::CaseInsensitiveEqualTo cmp;
1624 return cmp( lhs.original, rhs.original );
1625 }
1626
1627 Detail::unique_ptr<TestCaseInfo>
1628 makeTestCaseInfo(StringRef _className,
1629 NameAndTags const& nameAndTags,
1630 SourceLineInfo const& _lineInfo ) {
1631 return Detail::make_unique<TestCaseInfo>(_className, nameAndTags, _lineInfo);
1632 }
1633
1634 TestCaseInfo::TestCaseInfo(StringRef _className,
1635 NameAndTags const& _nameAndTags,
1636 SourceLineInfo const& _lineInfo):
1637 name( _nameAndTags.name.empty() ? makeDefaultName() : _nameAndTags.name ),
1638 className( _className ),
1639 lineInfo( _lineInfo )
1640 {
1641 StringRef originalTags = _nameAndTags.tags;
1642 // We need to reserve enough space to store all of the tags
1643 // (including optional hidden tag and filename tag)
1644 auto requiredSize = originalTags.size() + sizeOfExtraTags(_lineInfo.file);
1645 backingTags.reserve(requiredSize);
1646
1647 // We cannot copy the tags directly, as we need to normalize
1648 // some tags, so that [.foo] is copied as [.][foo].
1649 size_t tagStart = 0;
1650 size_t tagEnd = 0;
1651 bool inTag = false;
1652 for (size_t idx = 0; idx < originalTags.size(); ++idx) {
1653 auto c = originalTags[idx];
1654 if (c == '[') {
1655 CATCH_ENFORCE(
1656 !inTag,
1657 "Found '[' inside a tag while registering test case '"
1658 << _nameAndTags.name << "' at " << _lineInfo );
1659
1660 inTag = true;
1661 tagStart = idx;
1662 }
1663 if (c == ']') {
1664 CATCH_ENFORCE(
1665 inTag,
1666 "Found unmatched ']' while registering test case '"
1667 << _nameAndTags.name << "' at " << _lineInfo );
1668
1669 inTag = false;
1670 tagEnd = idx;
1671 assert(tagStart < tagEnd);
1672
1673 // We need to check the tag for special meanings, copy
1674 // it over to backing storage and actually reference the
1675 // backing storage in the saved tags
1676 StringRef tagStr = originalTags.substr(tagStart+1, tagEnd - tagStart - 1);
1677 CATCH_ENFORCE( !tagStr.empty(),
1678 "Found an empty tag while registering test case '"
1679 << _nameAndTags.name << "' at "
1680 << _lineInfo );
1681
1682 enforceNotReservedTag(tagStr, lineInfo);
1683 properties |= parseSpecialTag(tagStr);
1684 // When copying a tag to the backing storage, we need to
1685 // check if it is a merged hide tag, such as [.foo], and
1686 // if it is, we need to handle it as if it was [foo].
1687 if (tagStr.size() > 1 && tagStr[0] == '.') {
1688 tagStr = tagStr.substr(1, tagStr.size() - 1);
1689 }
1690 // We skip over dealing with the [.] tag, as we will add
1691 // it later unconditionally and then sort and unique all
1692 // the tags.
1693 internalAppendTag(tagStr);
1694 }
1695 }
1696 CATCH_ENFORCE( !inTag,
1697 "Found an unclosed tag while registering test case '"
1698 << _nameAndTags.name << "' at " << _lineInfo );
1699
1700
1701 // Add [.] if relevant
1702 if (isHidden()) {
1703 internalAppendTag("."_sr);
1704 }
1705
1706 // Sort and prepare tags
1707 std::sort(begin(tags), end(tags));
1708 tags.erase(std::unique(begin(tags), end(tags)),
1709 end(tags));
1710 }
1711
1712 bool TestCaseInfo::isHidden() const {
1713 return applies( properties & TestCaseProperties::IsHidden );
1714 }
1715 bool TestCaseInfo::throws() const {
1716 return applies( properties & TestCaseProperties::Throws );
1717 }
1718 bool TestCaseInfo::okToFail() const {
1719 return applies( properties & (TestCaseProperties::ShouldFail | TestCaseProperties::MayFail ) );
1720 }
1721 bool TestCaseInfo::expectedToFail() const {
1722 return applies( properties & (TestCaseProperties::ShouldFail) );
1723 }
1724
1725 void TestCaseInfo::addFilenameTag() {
1726 std::string combined("#");
1727 combined += extractFilenamePart(lineInfo.file);
1728 internalAppendTag(combined);
1729 }
1730
1731 std::string TestCaseInfo::tagsAsString() const {
1732 std::string ret;
1733 // '[' and ']' per tag
1734 std::size_t full_size = 2 * tags.size();
1735 for (const auto& tag : tags) {
1736 full_size += tag.original.size();
1737 }
1738 ret.reserve(full_size);
1739 for (const auto& tag : tags) {
1740 ret.push_back('[');
1741 ret += tag.original;
1742 ret.push_back(']');
1743 }
1744
1745 return ret;
1746 }
1747
1748 void TestCaseInfo::internalAppendTag(StringRef tagStr) {
1749 backingTags += '[';
1750 const auto backingStart = backingTags.size();
1751 backingTags += tagStr;
1752 const auto backingEnd = backingTags.size();
1753 backingTags += ']';
1754 tags.emplace_back(StringRef(backingTags.c_str() + backingStart, backingEnd - backingStart));
1755 }
1756
1757 bool operator<( TestCaseInfo const& lhs, TestCaseInfo const& rhs ) {
1758 // We want to avoid redoing the string comparisons multiple times,
1759 // so we store the result of a three-way comparison before using
1760 // it in the actual comparison logic.
1761 const auto cmpName = lhs.name.compare( rhs.name );
1762 if ( cmpName != 0 ) {
1763 return cmpName < 0;
1764 }
1765 const auto cmpClassName = lhs.className.compare( rhs.className );
1766 if ( cmpClassName != 0 ) {
1767 return cmpClassName < 0;
1768 }
1769 return lhs.tags < rhs.tags;
1770 }
1771
1772} // end namespace Catch
1773
1774
1775
1776#include <algorithm>
1777#include <string>
1778#include <vector>
1779#include <ostream>
1780
1781namespace Catch {
1782
1783 TestSpec::Pattern::Pattern( std::string const& name )
1784 : m_name( name )
1785 {}
1786
1787 TestSpec::Pattern::~Pattern() = default;
1788
1789 std::string const& TestSpec::Pattern::name() const {
1790 return m_name;
1791 }
1792
1793
1794 TestSpec::NamePattern::NamePattern( std::string const& name, std::string const& filterString )
1795 : Pattern( filterString )
1796 , m_wildcardPattern( toLower( name ), CaseSensitive::No )
1797 {}
1798
1799 bool TestSpec::NamePattern::matches( TestCaseInfo const& testCase ) const {
1800 return m_wildcardPattern.matches( testCase.name );
1801 }
1802
1803 void TestSpec::NamePattern::serializeTo( std::ostream& out ) const {
1804 out << '"' << name() << '"';
1805 }
1806
1807
1808 TestSpec::TagPattern::TagPattern( std::string const& tag, std::string const& filterString )
1809 : Pattern( filterString )
1810 , m_tag( tag )
1811 {}
1812
1813 bool TestSpec::TagPattern::matches( TestCaseInfo const& testCase ) const {
1814 return std::find( begin( testCase.tags ),
1815 end( testCase.tags ),
1816 Tag( m_tag ) ) != end( testCase.tags );
1817 }
1818
1819 void TestSpec::TagPattern::serializeTo( std::ostream& out ) const {
1820 out << name();
1821 }
1822
1823 bool TestSpec::Filter::matches( TestCaseInfo const& testCase ) const {
1824 bool should_use = !testCase.isHidden();
1825 for (auto const& pattern : m_required) {
1826 should_use = true;
1827 if (!pattern->matches(testCase)) {
1828 return false;
1829 }
1830 }
1831 for (auto const& pattern : m_forbidden) {
1832 if (pattern->matches(testCase)) {
1833 return false;
1834 }
1835 }
1836 return should_use;
1837 }
1838
1839 void TestSpec::Filter::serializeTo( std::ostream& out ) const {
1840 bool first = true;
1841 for ( auto const& pattern : m_required ) {
1842 if ( !first ) {
1843 out << ' ';
1844 }
1845 out << *pattern;
1846 first = false;
1847 }
1848 for ( auto const& pattern : m_forbidden ) {
1849 if ( !first ) {
1850 out << ' ';
1851 }
1852 out << *pattern;
1853 first = false;
1854 }
1855 }
1856
1857
1858 std::string TestSpec::extractFilterName( Filter const& filter ) {
1859 Catch::ReusableStringStream sstr;
1860 sstr << filter;
1861 return sstr.str();
1862 }
1863
1864 bool TestSpec::hasFilters() const {
1865 return !m_filters.empty();
1866 }
1867
1868 bool TestSpec::matches( TestCaseInfo const& testCase ) const {
1869 return std::any_of( m_filters.begin(), m_filters.end(), [&]( Filter const& f ){ return f.matches( testCase ); } );
1870 }
1871
1872 TestSpec::Matches TestSpec::matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const {
1873 Matches matches;
1874 matches.reserve( m_filters.size() );
1875 for ( auto const& filter : m_filters ) {
1876 std::vector<TestCaseHandle const*> currentMatches;
1877 for ( auto const& test : testCases )
1878 if ( isThrowSafe( test, config ) &&
1879 filter.matches( test.getTestCaseInfo() ) )
1880 currentMatches.emplace_back( &test );
1881 matches.push_back(
1882 FilterMatch{ extractFilterName( filter ), currentMatches } );
1883 }
1884 return matches;
1885 }
1886
1887 const TestSpec::vectorStrings& TestSpec::getInvalidSpecs() const {
1888 return m_invalidSpecs;
1889 }
1890
1891 void TestSpec::serializeTo( std::ostream& out ) const {
1892 bool first = true;
1893 for ( auto const& filter : m_filters ) {
1894 if ( !first ) {
1895 out << ',';
1896 }
1897 out << filter;
1898 first = false;
1899 }
1900 }
1901
1902}
1903
1904
1905
1906#include <chrono>
1907
1908namespace Catch {
1909
1910 namespace {
1911 static auto getCurrentNanosecondsSinceEpoch() -> uint64_t {
1912 return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now().time_since_epoch()).count();
1913 }
1914 } // end unnamed namespace
1915
1916 void Timer::start() {
1917 m_nanoseconds = getCurrentNanosecondsSinceEpoch();
1918 }
1919 auto Timer::getElapsedNanoseconds() const -> uint64_t {
1920 return getCurrentNanosecondsSinceEpoch() - m_nanoseconds;
1921 }
1922 auto Timer::getElapsedMicroseconds() const -> uint64_t {
1923 return getElapsedNanoseconds()/1000;
1924 }
1925 auto Timer::getElapsedMilliseconds() const -> unsigned int {
1926 return static_cast<unsigned int>(getElapsedMicroseconds()/1000);
1927 }
1928 auto Timer::getElapsedSeconds() const -> double {
1929 return getElapsedMicroseconds()/1000000.0;
1930 }
1931
1932
1933} // namespace Catch
1934
1935
1936
1937
1938#include <cmath>
1939#include <iomanip>
1940
1941namespace Catch {
1942
1943namespace Detail {
1944
1945 namespace {
1946 const int hexThreshold = 255;
1947
1948 struct Endianness {
1949 enum Arch { Big, Little };
1950
1951 static Arch which() {
1952 int one = 1;
1953 // If the lowest byte we read is non-zero, we can assume
1954 // that little endian format is used.
1955 auto value = *reinterpret_cast<char*>(&one);
1956 return value ? Little : Big;
1957 }
1958 };
1959
1960 template<typename T>
1961 std::string fpToString(T value, int precision) {
1962 if (Catch::isnan(value)) {
1963 return "nan";
1964 }
1965
1966 ReusableStringStream rss;
1967 rss << std::setprecision(precision)
1968 << std::fixed
1969 << value;
1970 std::string d = rss.str();
1971 std::size_t i = d.find_last_not_of('0');
1972 if (i != std::string::npos && i != d.size() - 1) {
1973 if (d[i] == '.')
1974 i++;
1975 d = d.substr(0, i + 1);
1976 }
1977 return d;
1978 }
1979 } // end unnamed namespace
1980
1981 std::string convertIntoString(StringRef string, bool escapeInvisibles) {
1982 std::string ret;
1983 // This is enough for the "don't escape invisibles" case, and a good
1984 // lower bound on the "escape invisibles" case.
1985 ret.reserve(string.size() + 2);
1986
1987 if (!escapeInvisibles) {
1988 ret += '"';
1989 ret += string;
1990 ret += '"';
1991 return ret;
1992 }
1993
1994 ret += '"';
1995 for (char c : string) {
1996 switch (c) {
1997 case '\r':
1998 ret.append("\\r");
1999 break;
2000 case '\n':
2001 ret.append("\\n");
2002 break;
2003 case '\t':
2004 ret.append("\\t");
2005 break;
2006 case '\f':
2007 ret.append("\\f");
2008 break;
2009 default:
2010 ret.push_back(c);
2011 break;
2012 }
2013 }
2014 ret += '"';
2015
2016 return ret;
2017 }
2018
2019 std::string convertIntoString(StringRef string) {
2020 return convertIntoString(string, getCurrentContext().getConfig()->showInvisibles());
2021 }
2022
2023 std::string rawMemoryToString( const void *object, std::size_t size ) {
2024 // Reverse order for little endian architectures
2025 int i = 0, end = static_cast<int>( size ), inc = 1;
2026 if( Endianness::which() == Endianness::Little ) {
2027 i = end-1;
2028 end = inc = -1;
2029 }
2030
2031 unsigned char const *bytes = static_cast<unsigned char const *>(object);
2032 ReusableStringStream rss;
2033 rss << "0x" << std::setfill('0') << std::hex;
2034 for( ; i != end; i += inc )
2035 rss << std::setw(2) << static_cast<unsigned>(bytes[i]);
2036 return rss.str();
2037 }
2038} // end Detail namespace
2039
2040
2041
2042//// ======================================================= ////
2043//
2044// Out-of-line defs for full specialization of StringMaker
2045//
2046//// ======================================================= ////
2047
2048std::string StringMaker<std::string>::convert(const std::string& str) {
2049 return Detail::convertIntoString( str );
2050}
2051
2052#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2053std::string StringMaker<std::string_view>::convert(std::string_view str) {
2054 return Detail::convertIntoString( StringRef( str.data(), str.size() ) );
2055}
2056#endif
2057
2058std::string StringMaker<char const*>::convert(char const* str) {
2059 if (str) {
2060 return Detail::convertIntoString( str );
2061 } else {
2062 return{ "{null string}" };
2063 }
2064}
2065std::string StringMaker<char*>::convert(char* str) { // NOLINT(readability-non-const-parameter)
2066 if (str) {
2067 return Detail::convertIntoString( str );
2068 } else {
2069 return{ "{null string}" };
2070 }
2071}
2072
2073#ifdef CATCH_CONFIG_WCHAR
2074std::string StringMaker<std::wstring>::convert(const std::wstring& wstr) {
2075 std::string s;
2076 s.reserve(wstr.size());
2077 for (auto c : wstr) {
2078 s += (c <= 0xff) ? static_cast<char>(c) : '?';
2079 }
2080 return ::Catch::Detail::stringify(s);
2081}
2082
2083# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2084std::string StringMaker<std::wstring_view>::convert(std::wstring_view str) {
2085 return StringMaker<std::wstring>::convert(std::wstring(str));
2086}
2087# endif
2088
2089std::string StringMaker<wchar_t const*>::convert(wchar_t const * str) {
2090 if (str) {
2091 return ::Catch::Detail::stringify(std::wstring{ str });
2092 } else {
2093 return{ "{null string}" };
2094 }
2095}
2096std::string StringMaker<wchar_t *>::convert(wchar_t * str) {
2097 if (str) {
2098 return ::Catch::Detail::stringify(std::wstring{ str });
2099 } else {
2100 return{ "{null string}" };
2101 }
2102}
2103#endif
2104
2105#if defined(CATCH_CONFIG_CPP17_BYTE)
2106#include <cstddef>
2107std::string StringMaker<std::byte>::convert(std::byte value) {
2108 return ::Catch::Detail::stringify(std::to_integer<unsigned long long>(value));
2109}
2110#endif // defined(CATCH_CONFIG_CPP17_BYTE)
2111
2112std::string StringMaker<int>::convert(int value) {
2113 return ::Catch::Detail::stringify(static_cast<long long>(value));
2114}
2115std::string StringMaker<long>::convert(long value) {
2116 return ::Catch::Detail::stringify(static_cast<long long>(value));
2117}
2118std::string StringMaker<long long>::convert(long long value) {
2119 ReusableStringStream rss;
2120 rss << value;
2121 if (value > Detail::hexThreshold) {
2122 rss << " (0x" << std::hex << value << ')';
2123 }
2124 return rss.str();
2125}
2126
2127std::string StringMaker<unsigned int>::convert(unsigned int value) {
2128 return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2129}
2130std::string StringMaker<unsigned long>::convert(unsigned long value) {
2131 return ::Catch::Detail::stringify(static_cast<unsigned long long>(value));
2132}
2133std::string StringMaker<unsigned long long>::convert(unsigned long long value) {
2134 ReusableStringStream rss;
2135 rss << value;
2136 if (value > Detail::hexThreshold) {
2137 rss << " (0x" << std::hex << value << ')';
2138 }
2139 return rss.str();
2140}
2141
2142std::string StringMaker<signed char>::convert(signed char value) {
2143 if (value == '\r') {
2144 return "'\\r'";
2145 } else if (value == '\f') {
2146 return "'\\f'";
2147 } else if (value == '\n') {
2148 return "'\\n'";
2149 } else if (value == '\t') {
2150 return "'\\t'";
2151 } else if ('\0' <= value && value < ' ') {
2152 return ::Catch::Detail::stringify(static_cast<unsigned int>(value));
2153 } else {
2154 char chstr[] = "' '";
2155 chstr[1] = value;
2156 return chstr;
2157 }
2158}
2159std::string StringMaker<char>::convert(char c) {
2160 return ::Catch::Detail::stringify(static_cast<signed char>(c));
2161}
2162std::string StringMaker<unsigned char>::convert(unsigned char value) {
2163 return ::Catch::Detail::stringify(static_cast<char>(value));
2164}
2165
2166int StringMaker<float>::precision = std::numeric_limits<float>::max_digits10;
2167
2168std::string StringMaker<float>::convert(float value) {
2169 return Detail::fpToString(value, precision) + 'f';
2170}
2171
2172int StringMaker<double>::precision = std::numeric_limits<double>::max_digits10;
2173
2174std::string StringMaker<double>::convert(double value) {
2175 return Detail::fpToString(value, precision);
2176}
2177
2178} // end namespace Catch
2179
2180
2181
2182namespace Catch {
2183
2184 Counts Counts::operator - ( Counts const& other ) const {
2185 Counts diff;
2186 diff.passed = passed - other.passed;
2187 diff.failed = failed - other.failed;
2188 diff.failedButOk = failedButOk - other.failedButOk;
2189 diff.skipped = skipped - other.skipped;
2190 return diff;
2191 }
2192
2193 Counts& Counts::operator += ( Counts const& other ) {
2194 passed += other.passed;
2195 failed += other.failed;
2196 failedButOk += other.failedButOk;
2197 skipped += other.skipped;
2198 return *this;
2199 }
2200
2201 std::uint64_t Counts::total() const {
2202 return passed + failed + failedButOk + skipped;
2203 }
2204 bool Counts::allPassed() const {
2205 return failed == 0 && failedButOk == 0 && skipped == 0;
2206 }
2207 bool Counts::allOk() const {
2208 return failed == 0;
2209 }
2210
2211 Totals Totals::operator - ( Totals const& other ) const {
2212 Totals diff;
2213 diff.assertions = assertions - other.assertions;
2214 diff.testCases = testCases - other.testCases;
2215 return diff;
2216 }
2217
2218 Totals& Totals::operator += ( Totals const& other ) {
2219 assertions += other.assertions;
2220 testCases += other.testCases;
2221 return *this;
2222 }
2223
2224 Totals Totals::delta( Totals const& prevTotals ) const {
2225 Totals diff = *this - prevTotals;
2226 if( diff.assertions.failed > 0 )
2227 ++diff.testCases.failed;
2228 else if( diff.assertions.failedButOk > 0 )
2229 ++diff.testCases.failedButOk;
2230 else if ( diff.assertions.skipped > 0 )
2231 ++ diff.testCases.skipped;
2232 else
2233 ++diff.testCases.passed;
2234 return diff;
2235 }
2236
2237}
2238
2239
2240
2241
2242namespace Catch {
2243 namespace Detail {
2244 void registerTranslatorImpl(
2245 Detail::unique_ptr<IExceptionTranslator>&& translator ) {
2246 getMutableRegistryHub().registerTranslator(
2247 CATCH_MOVE( translator ) );
2248 }
2249 } // namespace Detail
2250} // namespace Catch
2251
2252
2253#include <ostream>
2254
2255namespace Catch {
2256
2257 Version::Version
2258 ( unsigned int _majorVersion,
2259 unsigned int _minorVersion,
2260 unsigned int _patchNumber,
2261 char const * const _branchName,
2262 unsigned int _buildNumber )
2263 : majorVersion( _majorVersion ),
2264 minorVersion( _minorVersion ),
2265 patchNumber( _patchNumber ),
2266 branchName( _branchName ),
2267 buildNumber( _buildNumber )
2268 {}
2269
2270 std::ostream& operator << ( std::ostream& os, Version const& version ) {
2271 os << version.majorVersion << '.'
2272 << version.minorVersion << '.'
2273 << version.patchNumber;
2274 // branchName is never null -> 0th char is \0 if it is empty
2275 if (version.branchName[0]) {
2276 os << '-' << version.branchName
2277 << '.' << version.buildNumber;
2278 }
2279 return os;
2280 }
2281
2282 Version const& libraryVersion() {
2283 static Version version( 3, 7, 1, "", 0 );
2284 return version;
2285 }
2286
2287}
2288
2289
2290
2291
2292namespace Catch {
2293
2294 const char* GeneratorException::what() const noexcept {
2295 return m_msg;
2296 }
2297
2298} // end namespace Catch
2299
2300
2301
2302
2303namespace Catch {
2304
2305 IGeneratorTracker::~IGeneratorTracker() = default;
2306
2307namespace Generators {
2308
2309namespace Detail {
2310
2311 [[noreturn]]
2312 void throw_generator_exception(char const* msg) {
2313 Catch::throw_exception(GeneratorException{ msg });
2314 }
2315} // end namespace Detail
2316
2317 GeneratorUntypedBase::~GeneratorUntypedBase() = default;
2318
2319 IGeneratorTracker* acquireGeneratorTracker(StringRef generatorName, SourceLineInfo const& lineInfo ) {
2320 return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo );
2321 }
2322
2323 IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
2324 SourceLineInfo lineInfo,
2325 GeneratorBasePtr&& generator ) {
2326 return getResultCapture().createGeneratorTracker(
2327 generatorName, lineInfo, CATCH_MOVE( generator ) );
2328 }
2329
2330} // namespace Generators
2331} // namespace Catch
2332
2333
2334
2335
2336#include <random>
2337
2338namespace Catch {
2339 namespace Generators {
2340 namespace Detail {
2341 std::uint32_t getSeed() { return sharedRng()(); }
2342 } // namespace Detail
2343
2344 struct RandomFloatingGenerator<long double>::PImpl {
2345 PImpl( long double a, long double b, uint32_t seed ):
2346 rng( seed ), dist( a, b ) {}
2347
2348 Catch::SimplePcg32 rng;
2349 std::uniform_real_distribution<long double> dist;
2350 };
2351
2352 RandomFloatingGenerator<long double>::RandomFloatingGenerator(
2353 long double a, long double b, std::uint32_t seed) :
2354 m_pimpl(Catch::Detail::make_unique<PImpl>(a, b, seed)) {
2355 static_cast<void>( next() );
2356 }
2357
2358 RandomFloatingGenerator<long double>::~RandomFloatingGenerator() =
2359 default;
2360 bool RandomFloatingGenerator<long double>::next() {
2361 m_current_number = m_pimpl->dist( m_pimpl->rng );
2362 return true;
2363 }
2364 } // namespace Generators
2365} // namespace Catch
2366
2367
2368
2369
2370namespace Catch {
2371 IResultCapture::~IResultCapture() = default;
2372}
2373
2374
2375
2376
2377namespace Catch {
2378 IConfig::~IConfig() = default;
2379}
2380
2381
2382
2383
2384namespace Catch {
2385 IExceptionTranslator::~IExceptionTranslator() = default;
2386 IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() = default;
2387}
2388
2389
2390
2391#include <string>
2392
2393namespace Catch {
2394 namespace Generators {
2395
2396 bool GeneratorUntypedBase::countedNext() {
2397 auto ret = next();
2398 if ( ret ) {
2399 m_stringReprCache.clear();
2400 ++m_currentElementIndex;
2401 }
2402 return ret;
2403 }
2404
2405 StringRef GeneratorUntypedBase::currentElementAsString() const {
2406 if ( m_stringReprCache.empty() ) {
2407 m_stringReprCache = stringifyImpl();
2408 }
2409 return m_stringReprCache;
2410 }
2411
2412 } // namespace Generators
2413} // namespace Catch
2414
2415
2416
2417
2418namespace Catch {
2419 IRegistryHub::~IRegistryHub() = default;
2420 IMutableRegistryHub::~IMutableRegistryHub() = default;
2421}
2422
2423
2424
2425#include <cassert>
2426
2427namespace Catch {
2428
2429 ReporterConfig::ReporterConfig(
2430 IConfig const* _fullConfig,
2431 Detail::unique_ptr<IStream> _stream,
2432 ColourMode colourMode,
2433 std::map<std::string, std::string> customOptions ):
2434 m_stream( CATCH_MOVE(_stream) ),
2435 m_fullConfig( _fullConfig ),
2436 m_colourMode( colourMode ),
2437 m_customOptions( CATCH_MOVE( customOptions ) ) {}
2438
2439 Detail::unique_ptr<IStream> ReporterConfig::takeStream() && {
2440 assert( m_stream );
2441 return CATCH_MOVE( m_stream );
2442 }
2443 IConfig const * ReporterConfig::fullConfig() const { return m_fullConfig; }
2444 ColourMode ReporterConfig::colourMode() const { return m_colourMode; }
2445
2446 std::map<std::string, std::string> const&
2447 ReporterConfig::customOptions() const {
2448 return m_customOptions;
2449 }
2450
2451 ReporterConfig::~ReporterConfig() = default;
2452
2453 AssertionStats::AssertionStats( AssertionResult const& _assertionResult,
2454 std::vector<MessageInfo> const& _infoMessages,
2455 Totals const& _totals )
2456 : assertionResult( _assertionResult ),
2457 infoMessages( _infoMessages ),
2458 totals( _totals )
2459 {
2460 if( assertionResult.hasMessage() ) {
2461 // Copy message into messages list.
2462 // !TBD This should have been done earlier, somewhere
2463 MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
2464 builder.m_info.message = static_cast<std::string>(assertionResult.getMessage());
2465
2466 infoMessages.push_back( CATCH_MOVE(builder.m_info) );
2467 }
2468 }
2469
2470 SectionStats::SectionStats( SectionInfo&& _sectionInfo,
2471 Counts const& _assertions,
2472 double _durationInSeconds,
2473 bool _missingAssertions )
2474 : sectionInfo( CATCH_MOVE(_sectionInfo) ),
2475 assertions( _assertions ),
2476 durationInSeconds( _durationInSeconds ),
2477 missingAssertions( _missingAssertions )
2478 {}
2479
2480
2481 TestCaseStats::TestCaseStats( TestCaseInfo const& _testInfo,
2482 Totals const& _totals,
2483 std::string&& _stdOut,
2484 std::string&& _stdErr,
2485 bool _aborting )
2486 : testInfo( &_testInfo ),
2487 totals( _totals ),
2488 stdOut( CATCH_MOVE(_stdOut) ),
2489 stdErr( CATCH_MOVE(_stdErr) ),
2490 aborting( _aborting )
2491 {}
2492
2493
2494 TestRunStats::TestRunStats( TestRunInfo const& _runInfo,
2495 Totals const& _totals,
2496 bool _aborting )
2497 : runInfo( _runInfo ),
2498 totals( _totals ),
2499 aborting( _aborting )
2500 {}
2501
2502 IEventListener::~IEventListener() = default;
2503
2504} // end namespace Catch
2505
2506
2507
2508
2509namespace Catch {
2510 IReporterFactory::~IReporterFactory() = default;
2511 EventListenerFactory::~EventListenerFactory() = default;
2512}
2513
2514
2515
2516
2517namespace Catch {
2518 ITestCaseRegistry::~ITestCaseRegistry() = default;
2519}
2520
2521
2522
2523namespace Catch {
2524
2525 AssertionHandler::AssertionHandler
2526 ( StringRef macroName,
2527 SourceLineInfo const& lineInfo,
2528 StringRef capturedExpression,
2529 ResultDisposition::Flags resultDisposition )
2530 : m_assertionInfo{ macroName, lineInfo, capturedExpression, resultDisposition },
2531 m_resultCapture( getResultCapture() )
2532 {
2533 m_resultCapture.notifyAssertionStarted( m_assertionInfo );
2534 }
2535
2536 void AssertionHandler::handleExpr( ITransientExpression const& expr ) {
2537 m_resultCapture.handleExpr( m_assertionInfo, expr, m_reaction );
2538 }
2539 void AssertionHandler::handleMessage(ResultWas::OfType resultType, std::string&& message) {
2540 m_resultCapture.handleMessage( m_assertionInfo, resultType, CATCH_MOVE(message), m_reaction );
2541 }
2542
2543 auto AssertionHandler::allowThrows() const -> bool {
2544 return getCurrentContext().getConfig()->allowThrows();
2545 }
2546
2547 void AssertionHandler::complete() {
2548 m_completed = true;
2549 if( m_reaction.shouldDebugBreak ) {
2550
2551 // If you find your debugger stopping you here then go one level up on the
2552 // call-stack for the code that caused it (typically a failed assertion)
2553
2554 // (To go back to the test and change execution, jump over the throw, next)
2555 CATCH_BREAK_INTO_DEBUGGER();
2556 }
2557 if (m_reaction.shouldThrow) {
2558 throw_test_failure_exception();
2559 }
2560 if ( m_reaction.shouldSkip ) {
2561 throw_test_skip_exception();
2562 }
2563 }
2564
2565 void AssertionHandler::handleUnexpectedInflightException() {
2566 m_resultCapture.handleUnexpectedInflightException( m_assertionInfo, Catch::translateActiveException(), m_reaction );
2567 }
2568
2569 void AssertionHandler::handleExceptionThrownAsExpected() {
2570 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2571 }
2572 void AssertionHandler::handleExceptionNotThrownAsExpected() {
2573 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2574 }
2575
2576 void AssertionHandler::handleUnexpectedExceptionNotThrown() {
2577 m_resultCapture.handleUnexpectedExceptionNotThrown( m_assertionInfo, m_reaction );
2578 }
2579
2580 void AssertionHandler::handleThrowingCallSkipped() {
2581 m_resultCapture.handleNonExpr(m_assertionInfo, ResultWas::Ok, m_reaction);
2582 }
2583
2584 // This is the overload that takes a string and infers the Equals matcher from it
2585 // The more general overload, that takes any string matcher, is in catch_capture_matchers.cpp
2586 void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str ) {
2587 handleExceptionMatchExpr( handler, Matchers::Equals( str ) );
2588 }
2589
2590} // namespace Catch
2591
2592
2593
2594
2595#include <algorithm>
2596
2597namespace Catch {
2598 namespace Detail {
2599
2600 bool CaseInsensitiveLess::operator()( StringRef lhs,
2601 StringRef rhs ) const {
2602 return std::lexicographical_compare(
2603 lhs.begin(), lhs.end(),
2604 rhs.begin(), rhs.end(),
2605 []( char l, char r ) { return toLower( l ) < toLower( r ); } );
2606 }
2607
2608 bool
2609 CaseInsensitiveEqualTo::operator()( StringRef lhs,
2610 StringRef rhs ) const {
2611 return std::equal(
2612 lhs.begin(), lhs.end(),
2613 rhs.begin(), rhs.end(),
2614 []( char l, char r ) { return toLower( l ) == toLower( r ); } );
2615 }
2616
2617 } // namespace Detail
2618} // namespace Catch
2619
2620
2621
2622
2623#include <algorithm>
2624#include <ostream>
2625
2626namespace {
2627 bool isOptPrefix( char c ) {
2628 return c == '-'
2629#ifdef CATCH_PLATFORM_WINDOWS
2630 || c == '/'
2631#endif
2632 ;
2633 }
2634
2635 Catch::StringRef normaliseOpt( Catch::StringRef optName ) {
2636 if ( optName[0] == '-'
2637#if defined(CATCH_PLATFORM_WINDOWS)
2638 || optName[0] == '/'
2639#endif
2640 ) {
2641 return optName.substr( 1, optName.size() );
2642 }
2643
2644 return optName;
2645 }
2646
2647 static size_t find_first_separator(Catch::StringRef sr) {
2648 auto is_separator = []( char c ) {
2649 return c == ' ' || c == ':' || c == '=';
2650 };
2651 size_t pos = 0;
2652 while (pos < sr.size()) {
2653 if (is_separator(sr[pos])) { return pos; }
2654 ++pos;
2655 }
2656
2657 return Catch::StringRef::npos;
2658 }
2659
2660} // namespace
2661
2662namespace Catch {
2663 namespace Clara {
2664 namespace Detail {
2665
2666 void TokenStream::loadBuffer() {
2667 m_tokenBuffer.clear();
2668
2669 // Skip any empty strings
2670 while ( it != itEnd && it->empty() ) {
2671 ++it;
2672 }
2673
2674 if ( it != itEnd ) {
2675 StringRef next = *it;
2676 if ( isOptPrefix( next[0] ) ) {
2677 auto delimiterPos = find_first_separator(next);
2678 if ( delimiterPos != StringRef::npos ) {
2679 m_tokenBuffer.push_back(
2680 { TokenType::Option,
2681 next.substr( 0, delimiterPos ) } );
2682 m_tokenBuffer.push_back(
2683 { TokenType::Argument,
2684 next.substr( delimiterPos + 1, next.size() ) } );
2685 } else {
2686 if ( next.size() > 1 && next[1] != '-' && next.size() > 2 ) {
2687 // Combined short args, e.g. "-ab" for "-a -b"
2688 for ( size_t i = 1; i < next.size(); ++i ) {
2689 m_tokenBuffer.push_back(
2690 { TokenType::Option,
2691 next.substr( i, 1 ) } );
2692 }
2693 } else {
2694 m_tokenBuffer.push_back(
2695 { TokenType::Option, next } );
2696 }
2697 }
2698 } else {
2699 m_tokenBuffer.push_back(
2700 { TokenType::Argument, next } );
2701 }
2702 }
2703 }
2704
2705 TokenStream::TokenStream( Args const& args ):
2706 TokenStream( args.m_args.begin(), args.m_args.end() ) {}
2707
2708 TokenStream::TokenStream( Iterator it_, Iterator itEnd_ ):
2709 it( it_ ), itEnd( itEnd_ ) {
2710 loadBuffer();
2711 }
2712
2713 TokenStream& TokenStream::operator++() {
2714 if ( m_tokenBuffer.size() >= 2 ) {
2715 m_tokenBuffer.erase( m_tokenBuffer.begin() );
2716 } else {
2717 if ( it != itEnd )
2718 ++it;
2719 loadBuffer();
2720 }
2721 return *this;
2722 }
2723
2724 ParserResult convertInto( std::string const& source,
2725 std::string& target ) {
2726 target = source;
2727 return ParserResult::ok( ParseResultType::Matched );
2728 }
2729
2730 ParserResult convertInto( std::string const& source,
2731 bool& target ) {
2732 std::string srcLC = toLower( source );
2733
2734 if ( srcLC == "y" || srcLC == "1" || srcLC == "true" ||
2735 srcLC == "yes" || srcLC == "on" ) {
2736 target = true;
2737 } else if ( srcLC == "n" || srcLC == "0" || srcLC == "false" ||
2738 srcLC == "no" || srcLC == "off" ) {
2739 target = false;
2740 } else {
2741 return ParserResult::runtimeError(
2742 "Expected a boolean value but did not recognise: '" +
2743 source + '\'' );
2744 }
2745 return ParserResult::ok( ParseResultType::Matched );
2746 }
2747
2748 size_t ParserBase::cardinality() const { return 1; }
2749
2750 InternalParseResult ParserBase::parse( Args const& args ) const {
2751 return parse( static_cast<std::string>(args.exeName()), TokenStream( args ) );
2752 }
2753
2754 ParseState::ParseState( ParseResultType type,
2755 TokenStream remainingTokens ):
2756 m_type( type ), m_remainingTokens( CATCH_MOVE(remainingTokens) ) {}
2757
2758 ParserResult BoundFlagRef::setFlag( bool flag ) {
2759 m_ref = flag;
2760 return ParserResult::ok( ParseResultType::Matched );
2761 }
2762
2763 ResultBase::~ResultBase() = default;
2764
2765 bool BoundRef::isContainer() const { return false; }
2766
2767 bool BoundRef::isFlag() const { return false; }
2768
2769 bool BoundFlagRefBase::isFlag() const { return true; }
2770
2771} // namespace Detail
2772
2773 Detail::InternalParseResult Arg::parse(std::string const&,
2774 Detail::TokenStream tokens) const {
2775 auto validationResult = validate();
2776 if (!validationResult)
2777 return Detail::InternalParseResult(validationResult);
2778
2779 auto token = *tokens;
2780 if (token.type != Detail::TokenType::Argument)
2781 return Detail::InternalParseResult::ok(Detail::ParseState(
2782 ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2783
2784 assert(!m_ref->isFlag());
2785 auto valueRef =
2786 static_cast<Detail::BoundValueRefBase*>(m_ref.get());
2787
2788 auto result = valueRef->setValue(static_cast<std::string>(token.token));
2789 if ( !result )
2790 return Detail::InternalParseResult( result );
2791 else
2792 return Detail::InternalParseResult::ok(
2793 Detail::ParseState( ParseResultType::Matched,
2794 CATCH_MOVE( ++tokens ) ) );
2795 }
2796
2797 Opt::Opt(bool& ref) :
2798 ParserRefImpl(std::make_shared<Detail::BoundFlagRef>(ref)) {}
2799
2800 Detail::HelpColumns Opt::getHelpColumns() const {
2801 ReusableStringStream oss;
2802 bool first = true;
2803 for (auto const& opt : m_optNames) {
2804 if (first)
2805 first = false;
2806 else
2807 oss << ", ";
2808 oss << opt;
2809 }
2810 if (!m_hint.empty())
2811 oss << " <" << m_hint << '>';
2812 return { oss.str(), m_description };
2813 }
2814
2815 bool Opt::isMatch(StringRef optToken) const {
2816 auto normalisedToken = normaliseOpt(optToken);
2817 for (auto const& name : m_optNames) {
2818 if (normaliseOpt(name) == normalisedToken)
2819 return true;
2820 }
2821 return false;
2822 }
2823
2824 Detail::InternalParseResult Opt::parse(std::string const&,
2825 Detail::TokenStream tokens) const {
2826 auto validationResult = validate();
2827 if (!validationResult)
2828 return Detail::InternalParseResult(validationResult);
2829
2830 if (tokens &&
2831 tokens->type == Detail::TokenType::Option) {
2832 auto const& token = *tokens;
2833 if (isMatch(token.token)) {
2834 if (m_ref->isFlag()) {
2835 auto flagRef =
2836 static_cast<Detail::BoundFlagRefBase*>(
2837 m_ref.get());
2838 auto result = flagRef->setFlag(true);
2839 if (!result)
2840 return Detail::InternalParseResult(result);
2841 if (result.value() ==
2842 ParseResultType::ShortCircuitAll)
2843 return Detail::InternalParseResult::ok(Detail::ParseState(
2844 result.value(), CATCH_MOVE(tokens)));
2845 } else {
2846 auto valueRef =
2847 static_cast<Detail::BoundValueRefBase*>(
2848 m_ref.get());
2849 ++tokens;
2850 if (!tokens)
2851 return Detail::InternalParseResult::runtimeError(
2852 "Expected argument following " +
2853 token.token);
2854 auto const& argToken = *tokens;
2855 if (argToken.type != Detail::TokenType::Argument)
2856 return Detail::InternalParseResult::runtimeError(
2857 "Expected argument following " +
2858 token.token);
2859 const auto result = valueRef->setValue(static_cast<std::string>(argToken.token));
2860 if (!result)
2861 return Detail::InternalParseResult(result);
2862 if (result.value() ==
2863 ParseResultType::ShortCircuitAll)
2864 return Detail::InternalParseResult::ok(Detail::ParseState(
2865 result.value(), CATCH_MOVE(tokens)));
2866 }
2867 return Detail::InternalParseResult::ok(Detail::ParseState(
2868 ParseResultType::Matched, CATCH_MOVE(++tokens)));
2869 }
2870 }
2871 return Detail::InternalParseResult::ok(
2872 Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2873 }
2874
2875 Detail::Result Opt::validate() const {
2876 if (m_optNames.empty())
2877 return Detail::Result::logicError("No options supplied to Opt");
2878 for (auto const& name : m_optNames) {
2879 if (name.empty())
2880 return Detail::Result::logicError(
2881 "Option name cannot be empty");
2882#ifdef CATCH_PLATFORM_WINDOWS
2883 if (name[0] != '-' && name[0] != '/')
2884 return Detail::Result::logicError(
2885 "Option name must begin with '-' or '/'");
2886#else
2887 if (name[0] != '-')
2888 return Detail::Result::logicError(
2889 "Option name must begin with '-'");
2890#endif
2891 }
2892 return ParserRefImpl::validate();
2893 }
2894
2895 ExeName::ExeName() :
2896 m_name(std::make_shared<std::string>("<executable>")) {}
2897
2898 ExeName::ExeName(std::string& ref) : ExeName() {
2899 m_ref = std::make_shared<Detail::BoundValueRef<std::string>>(ref);
2900 }
2901
2902 Detail::InternalParseResult
2903 ExeName::parse(std::string const&,
2904 Detail::TokenStream tokens) const {
2905 return Detail::InternalParseResult::ok(
2906 Detail::ParseState(ParseResultType::NoMatch, CATCH_MOVE(tokens)));
2907 }
2908
2909 ParserResult ExeName::set(std::string const& newName) {
2910 auto lastSlash = newName.find_last_of("\\/");
2911 auto filename = (lastSlash == std::string::npos)
2912 ? newName
2913 : newName.substr(lastSlash + 1);
2914
2915 *m_name = filename;
2916 if (m_ref)
2917 return m_ref->setValue(filename);
2918 else
2919 return ParserResult::ok(ParseResultType::Matched);
2920 }
2921
2922
2923
2924
2925 Parser& Parser::operator|=( Parser const& other ) {
2926 m_options.insert( m_options.end(),
2927 other.m_options.begin(),
2928 other.m_options.end() );
2929 m_args.insert(
2930 m_args.end(), other.m_args.begin(), other.m_args.end() );
2931 return *this;
2932 }
2933
2934 std::vector<Detail::HelpColumns> Parser::getHelpColumns() const {
2935 std::vector<Detail::HelpColumns> cols;
2936 cols.reserve( m_options.size() );
2937 for ( auto const& o : m_options ) {
2938 cols.push_back(o.getHelpColumns());
2939 }
2940 return cols;
2941 }
2942
2943 void Parser::writeToStream( std::ostream& os ) const {
2944 if ( !m_exeName.name().empty() ) {
2945 os << "usage:\n"
2946 << " " << m_exeName.name() << ' ';
2947 bool required = true, first = true;
2948 for ( auto const& arg : m_args ) {
2949 if ( first )
2950 first = false;
2951 else
2952 os << ' ';
2953 if ( arg.isOptional() && required ) {
2954 os << '[';
2955 required = false;
2956 }
2957 os << '<' << arg.hint() << '>';
2958 if ( arg.cardinality() == 0 )
2959 os << " ... ";
2960 }
2961 if ( !required )
2962 os << ']';
2963 if ( !m_options.empty() )
2964 os << " options";
2965 os << "\n\nwhere options are:\n";
2966 }
2967
2968 auto rows = getHelpColumns();
2969 size_t consoleWidth = CATCH_CONFIG_CONSOLE_WIDTH;
2970 size_t optWidth = 0;
2971 for ( auto const& cols : rows )
2972 optWidth = ( std::max )( optWidth, cols.left.size() + 2 );
2973
2974 optWidth = ( std::min )( optWidth, consoleWidth / 2 );
2975
2976 for ( auto& cols : rows ) {
2977 auto row = TextFlow::Column( CATCH_MOVE(cols.left) )
2978 .width( optWidth )
2979 .indent( 2 ) +
2980 TextFlow::Spacer( 4 ) +
2981 TextFlow::Column( static_cast<std::string>(cols.descriptions) )
2982 .width( consoleWidth - 7 - optWidth );
2983 os << row << '\n';
2984 }
2985 }
2986
2987 Detail::Result Parser::validate() const {
2988 for ( auto const& opt : m_options ) {
2989 auto result = opt.validate();
2990 if ( !result )
2991 return result;
2992 }
2993 for ( auto const& arg : m_args ) {
2994 auto result = arg.validate();
2995 if ( !result )
2996 return result;
2997 }
2998 return Detail::Result::ok();
2999 }
3000
3001 Detail::InternalParseResult
3002 Parser::parse( std::string const& exeName,
3003 Detail::TokenStream tokens ) const {
3004
3005 struct ParserInfo {
3006 ParserBase const* parser = nullptr;
3007 size_t count = 0;
3008 };
3009 std::vector<ParserInfo> parseInfos;
3010 parseInfos.reserve( m_options.size() + m_args.size() );
3011 for ( auto const& opt : m_options ) {
3012 parseInfos.push_back( { &opt, 0 } );
3013 }
3014 for ( auto const& arg : m_args ) {
3015 parseInfos.push_back( { &arg, 0 } );
3016 }
3017
3018 m_exeName.set( exeName );
3019
3020 auto result = Detail::InternalParseResult::ok(
3021 Detail::ParseState( ParseResultType::NoMatch, CATCH_MOVE(tokens) ) );
3022 while ( result.value().remainingTokens() ) {
3023 bool tokenParsed = false;
3024
3025 for ( auto& parseInfo : parseInfos ) {
3026 if ( parseInfo.parser->cardinality() == 0 ||
3027 parseInfo.count < parseInfo.parser->cardinality() ) {
3028 result = parseInfo.parser->parse(
3029 exeName, CATCH_MOVE(result).value().remainingTokens() );
3030 if ( !result )
3031 return result;
3032 if ( result.value().type() !=
3033 ParseResultType::NoMatch ) {
3034 tokenParsed = true;
3035 ++parseInfo.count;
3036 break;
3037 }
3038 }
3039 }
3040
3041 if ( result.value().type() == ParseResultType::ShortCircuitAll )
3042 return result;
3043 if ( !tokenParsed )
3044 return Detail::InternalParseResult::runtimeError(
3045 "Unrecognised token: " +
3046 result.value().remainingTokens()->token );
3047 }
3048 // !TBD Check missing required options
3049 return result;
3050 }
3051
3052 Args::Args(int argc, char const* const* argv) :
3053 m_exeName(argv[0]), m_args(argv + 1, argv + argc) {}
3054
3055 Args::Args(std::initializer_list<StringRef> args) :
3056 m_exeName(*args.begin()),
3057 m_args(args.begin() + 1, args.end()) {}
3058
3059
3060 Help::Help( bool& showHelpFlag ):
3061 Opt( [&]( bool flag ) {
3062 showHelpFlag = flag;
3063 return ParserResult::ok( ParseResultType::ShortCircuitAll );
3064 } ) {
3065 static_cast<Opt&> ( *this )(
3066 "display usage information" )["-?"]["-h"]["--help"]
3067 .optional();
3068 }
3069
3070 } // namespace Clara
3071} // namespace Catch
3072
3073
3074
3075
3076#include <fstream>
3077#include <string>
3078
3079namespace Catch {
3080
3081 Clara::Parser makeCommandLineParser( ConfigData& config ) {
3082
3083 using namespace Clara;
3084
3085 auto const setWarning = [&]( std::string const& warning ) {
3086 if ( warning == "NoAssertions" ) {
3087 config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::NoAssertions);
3088 return ParserResult::ok( ParseResultType::Matched );
3089 } else if ( warning == "UnmatchedTestSpec" ) {
3090 config.warnings = static_cast<WarnAbout::What>(config.warnings | WarnAbout::UnmatchedTestSpec);
3091 return ParserResult::ok( ParseResultType::Matched );
3092 }
3093
3094 return ParserResult ::runtimeError(
3095 "Unrecognised warning option: '" + warning + '\'' );
3096 };
3097 auto const loadTestNamesFromFile = [&]( std::string const& filename ) {
3098 std::ifstream f( filename.c_str() );
3099 if( !f.is_open() )
3100 return ParserResult::runtimeError( "Unable to load input file: '" + filename + '\'' );
3101
3102 std::string line;
3103 while( std::getline( f, line ) ) {
3104 line = trim(line);
3105 if( !line.empty() && !startsWith( line, '#' ) ) {
3106 if( !startsWith( line, '"' ) )
3107 line = '"' + CATCH_MOVE(line) + '"';
3108 config.testsOrTags.push_back( line );
3109 config.testsOrTags.emplace_back( "," );
3110 }
3111 }
3112 //Remove comma in the end
3113 if(!config.testsOrTags.empty())
3114 config.testsOrTags.erase( config.testsOrTags.end()-1 );
3115
3116 return ParserResult::ok( ParseResultType::Matched );
3117 };
3118 auto const setTestOrder = [&]( std::string const& order ) {
3119 if( startsWith( "declared", order ) )
3120 config.runOrder = TestRunOrder::Declared;
3121 else if( startsWith( "lexical", order ) )
3122 config.runOrder = TestRunOrder::LexicographicallySorted;
3123 else if( startsWith( "random", order ) )
3124 config.runOrder = TestRunOrder::Randomized;
3125 else
3126 return ParserResult::runtimeError( "Unrecognised ordering: '" + order + '\'' );
3127 return ParserResult::ok( ParseResultType::Matched );
3128 };
3129 auto const setRngSeed = [&]( std::string const& seed ) {
3130 if( seed == "time" ) {
3131 config.rngSeed = generateRandomSeed(GenerateFrom::Time);
3132 return ParserResult::ok(ParseResultType::Matched);
3133 } else if (seed == "random-device") {
3134 config.rngSeed = generateRandomSeed(GenerateFrom::RandomDevice);
3135 return ParserResult::ok(ParseResultType::Matched);
3136 }
3137
3138 // TODO: ideally we should be parsing uint32_t directly
3139 // fix this later when we add new parse overload
3140 auto parsedSeed = parseUInt( seed, 0 );
3141 if ( !parsedSeed ) {
3142 return ParserResult::runtimeError( "Could not parse '" + seed + "' as seed" );
3143 }
3144 config.rngSeed = *parsedSeed;
3145 return ParserResult::ok( ParseResultType::Matched );
3146 };
3147 auto const setDefaultColourMode = [&]( std::string const& colourMode ) {
3148 Optional<ColourMode> maybeMode = Catch::Detail::stringToColourMode(toLower( colourMode ));
3149 if ( !maybeMode ) {
3150 return ParserResult::runtimeError(
3151 "colour mode must be one of: default, ansi, win32, "
3152 "or none. '" +
3153 colourMode + "' is not recognised" );
3154 }
3155 auto mode = *maybeMode;
3156 if ( !isColourImplAvailable( mode ) ) {
3157 return ParserResult::runtimeError(
3158 "colour mode '" + colourMode +
3159 "' is not supported in this binary" );
3160 }
3161 config.defaultColourMode = mode;
3162 return ParserResult::ok( ParseResultType::Matched );
3163 };
3164 auto const setWaitForKeypress = [&]( std::string const& keypress ) {
3165 auto keypressLc = toLower( keypress );
3166 if (keypressLc == "never")
3167 config.waitForKeypress = WaitForKeypress::Never;
3168 else if( keypressLc == "start" )
3169 config.waitForKeypress = WaitForKeypress::BeforeStart;
3170 else if( keypressLc == "exit" )
3171 config.waitForKeypress = WaitForKeypress::BeforeExit;
3172 else if( keypressLc == "both" )
3173 config.waitForKeypress = WaitForKeypress::BeforeStartAndExit;
3174 else
3175 return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" );
3176 return ParserResult::ok( ParseResultType::Matched );
3177 };
3178 auto const setVerbosity = [&]( std::string const& verbosity ) {
3179 auto lcVerbosity = toLower( verbosity );
3180 if( lcVerbosity == "quiet" )
3181 config.verbosity = Verbosity::Quiet;
3182 else if( lcVerbosity == "normal" )
3183 config.verbosity = Verbosity::Normal;
3184 else if( lcVerbosity == "high" )
3185 config.verbosity = Verbosity::High;
3186 else
3187 return ParserResult::runtimeError( "Unrecognised verbosity, '" + verbosity + '\'' );
3188 return ParserResult::ok( ParseResultType::Matched );
3189 };
3190 auto const setReporter = [&]( std::string const& userReporterSpec ) {
3191 if ( userReporterSpec.empty() ) {
3192 return ParserResult::runtimeError( "Received empty reporter spec." );
3193 }
3194
3195 Optional<ReporterSpec> parsed =
3196 parseReporterSpec( userReporterSpec );
3197 if ( !parsed ) {
3198 return ParserResult::runtimeError(
3199 "Could not parse reporter spec '" + userReporterSpec +
3200 "'" );
3201 }
3202
3203 auto const& reporterSpec = *parsed;
3204
3205 auto const& factories =
3206 getRegistryHub().getReporterRegistry().getFactories();
3207 auto result = factories.find( reporterSpec.name() );
3208
3209 if ( result == factories.end() ) {
3210 return ParserResult::runtimeError(
3211 "Unrecognized reporter, '" + reporterSpec.name() +
3212 "'. Check available with --list-reporters" );
3213 }
3214
3215
3216 const bool hadOutputFile = reporterSpec.outputFile().some();
3217 config.reporterSpecifications.push_back( CATCH_MOVE( *parsed ) );
3218 // It would be enough to check this only once at the very end, but
3219 // there is not a place where we could call this check, so do it
3220 // every time it could fail. For valid inputs, this is still called
3221 // at most once.
3222 if (!hadOutputFile) {
3223 int n_reporters_without_file = 0;
3224 for (auto const& spec : config.reporterSpecifications) {
3225 if (spec.outputFile().none()) {
3226 n_reporters_without_file++;
3227 }
3228 }
3229 if (n_reporters_without_file > 1) {
3230 return ParserResult::runtimeError( "Only one reporter may have unspecified output file." );
3231 }
3232 }
3233
3234 return ParserResult::ok( ParseResultType::Matched );
3235 };
3236 auto const setShardCount = [&]( std::string const& shardCount ) {
3237 auto parsedCount = parseUInt( shardCount );
3238 if ( !parsedCount ) {
3239 return ParserResult::runtimeError(
3240 "Could not parse '" + shardCount + "' as shard count" );
3241 }
3242 if ( *parsedCount == 0 ) {
3243 return ParserResult::runtimeError(
3244 "Shard count must be positive" );
3245 }
3246 config.shardCount = *parsedCount;
3247 return ParserResult::ok( ParseResultType::Matched );
3248 };
3249
3250 auto const setShardIndex = [&](std::string const& shardIndex) {
3251 auto parsedIndex = parseUInt( shardIndex );
3252 if ( !parsedIndex ) {
3253 return ParserResult::runtimeError(
3254 "Could not parse '" + shardIndex + "' as shard index" );
3255 }
3256 config.shardIndex = *parsedIndex;
3257 return ParserResult::ok( ParseResultType::Matched );
3258 };
3259
3260 auto cli
3261 = ExeName( config.processName )
3262 | Help( config.showHelp )
3263 | Opt( config.showSuccessfulTests )
3264 ["-s"]["--success"]
3265 ( "include successful tests in output" )
3266 | Opt( config.shouldDebugBreak )
3267 ["-b"]["--break"]
3268 ( "break into debugger on failure" )
3269 | Opt( config.noThrow )
3270 ["-e"]["--nothrow"]
3271 ( "skip exception tests" )
3272 | Opt( config.showInvisibles )
3273 ["-i"]["--invisibles"]
3274 ( "show invisibles (tabs, newlines)" )
3275 | Opt( config.defaultOutputFilename, "filename" )
3276 ["-o"]["--out"]
3277 ( "default output filename" )
3278 | Opt( accept_many, setReporter, "name[::key=value]*" )
3279 ["-r"]["--reporter"]
3280 ( "reporter to use (defaults to console)" )
3281 | Opt( config.name, "name" )
3282 ["-n"]["--name"]
3283 ( "suite name" )
3284 | Opt( [&]( bool ){ config.abortAfter = 1; } )
3285 ["-a"]["--abort"]
3286 ( "abort at first failure" )
3287 | Opt( [&]( int x ){ config.abortAfter = x; }, "no. failures" )
3288 ["-x"]["--abortx"]
3289 ( "abort after x failures" )
3290 | Opt( accept_many, setWarning, "warning name" )
3291 ["-w"]["--warn"]
3292 ( "enable warnings" )
3293 | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" )
3294 ["-d"]["--durations"]
3295 ( "show test durations" )
3296 | Opt( config.minDuration, "seconds" )
3297 ["-D"]["--min-duration"]
3298 ( "show test durations for tests taking at least the given number of seconds" )
3299 | Opt( loadTestNamesFromFile, "filename" )
3300 ["-f"]["--input-file"]
3301 ( "load test names to run from a file" )
3302 | Opt( config.filenamesAsTags )
3303 ["-#"]["--filenames-as-tags"]
3304 ( "adds a tag for the filename" )
3305 | Opt( config.sectionsToRun, "section name" )
3306 ["-c"]["--section"]
3307 ( "specify section to run" )
3308 | Opt( setVerbosity, "quiet|normal|high" )
3309 ["-v"]["--verbosity"]
3310 ( "set output verbosity" )
3311 | Opt( config.listTests )
3312 ["--list-tests"]
3313 ( "list all/matching test cases" )
3314 | Opt( config.listTags )
3315 ["--list-tags"]
3316 ( "list all/matching tags" )
3317 | Opt( config.listReporters )
3318 ["--list-reporters"]
3319 ( "list all available reporters" )
3320 | Opt( config.listListeners )
3321 ["--list-listeners"]
3322 ( "list all listeners" )
3323 | Opt( setTestOrder, "decl|lex|rand" )
3324 ["--order"]
3325 ( "test case order (defaults to decl)" )
3326 | Opt( setRngSeed, "'time'|'random-device'|number" )
3327 ["--rng-seed"]
3328 ( "set a specific seed for random numbers" )
3329 | Opt( setDefaultColourMode, "ansi|win32|none|default" )
3330 ["--colour-mode"]
3331 ( "what color mode should be used as default" )
3332 | Opt( config.libIdentify )
3333 ["--libidentify"]
3334 ( "report name and version according to libidentify standard" )
3335 | Opt( setWaitForKeypress, "never|start|exit|both" )
3336 ["--wait-for-keypress"]
3337 ( "waits for a keypress before exiting" )
3338 | Opt( config.skipBenchmarks)
3339 ["--skip-benchmarks"]
3340 ( "disable running benchmarks")
3341 | Opt( config.benchmarkSamples, "samples" )
3342 ["--benchmark-samples"]
3343 ( "number of samples to collect (default: 100)" )
3344 | Opt( config.benchmarkResamples, "resamples" )
3345 ["--benchmark-resamples"]
3346 ( "number of resamples for the bootstrap (default: 100000)" )
3347 | Opt( config.benchmarkConfidenceInterval, "confidence interval" )
3348 ["--benchmark-confidence-interval"]
3349 ( "confidence interval for the bootstrap (between 0 and 1, default: 0.95)" )
3350 | Opt( config.benchmarkNoAnalysis )
3351 ["--benchmark-no-analysis"]
3352 ( "perform only measurements; do not perform any analysis" )
3353 | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" )
3354 ["--benchmark-warmup-time"]
3355 ( "amount of time in milliseconds spent on warming up each test (default: 100)" )
3356 | Opt( setShardCount, "shard count" )
3357 ["--shard-count"]
3358 ( "split the tests to execute into this many groups" )
3359 | Opt( setShardIndex, "shard index" )
3360 ["--shard-index"]
3361 ( "index of the group of tests to execute (see --shard-count)" )
3362 | Opt( config.allowZeroTests )
3363 ["--allow-running-no-tests"]
3364 ( "Treat 'No tests run' as a success" )
3365 | Arg( config.testsOrTags, "test name|pattern|tags" )
3366 ( "which test or tests to use" );
3367
3368 return cli;
3369 }
3370
3371} // end namespace Catch
3372
3373
3374#if defined(__clang__)
3375# pragma clang diagnostic push
3376# pragma clang diagnostic ignored "-Wexit-time-destructors"
3377#endif
3378
3379
3380
3381#include <cassert>
3382#include <ostream>
3383#include <utility>
3384
3385namespace Catch {
3386
3387 ColourImpl::~ColourImpl() = default;
3388
3389 ColourImpl::ColourGuard ColourImpl::guardColour( Colour::Code colourCode ) {
3390 return ColourGuard(colourCode, this );
3391 }
3392
3393 void ColourImpl::ColourGuard::engageImpl( std::ostream& stream ) {
3394 assert( &stream == &m_colourImpl->m_stream->stream() &&
3395 "Engaging colour guard for different stream than used by the "
3396 "parent colour implementation" );
3397 static_cast<void>( stream );
3398
3399 m_engaged = true;
3400 m_colourImpl->use( m_code );
3401 }
3402
3403 ColourImpl::ColourGuard::ColourGuard( Colour::Code code,
3404 ColourImpl const* colour ):
3405 m_colourImpl( colour ), m_code( code ) {
3406 }
3407 ColourImpl::ColourGuard::ColourGuard( ColourGuard&& rhs ) noexcept:
3408 m_colourImpl( rhs.m_colourImpl ),
3409 m_code( rhs.m_code ),
3410 m_engaged( rhs.m_engaged ) {
3411 rhs.m_engaged = false;
3412 }
3413 ColourImpl::ColourGuard&
3414 ColourImpl::ColourGuard::operator=( ColourGuard&& rhs ) noexcept {
3415 using std::swap;
3416 swap( m_colourImpl, rhs.m_colourImpl );
3417 swap( m_code, rhs.m_code );
3418 swap( m_engaged, rhs.m_engaged );
3419
3420 return *this;
3421 }
3422 ColourImpl::ColourGuard::~ColourGuard() {
3423 if ( m_engaged ) {
3424 m_colourImpl->use( Colour::None );
3425 }
3426 }
3427
3428 ColourImpl::ColourGuard&
3429 ColourImpl::ColourGuard::engage( std::ostream& stream ) & {
3430 engageImpl( stream );
3431 return *this;
3432 }
3433
3434 ColourImpl::ColourGuard&&
3435 ColourImpl::ColourGuard::engage( std::ostream& stream ) && {
3436 engageImpl( stream );
3437 return CATCH_MOVE(*this);
3438 }
3439
3440 namespace {
3441 //! A do-nothing implementation of colour, used as fallback for unknown
3442 //! platforms, and when the user asks to deactivate all colours.
3443 class NoColourImpl final : public ColourImpl {
3444 public:
3445 NoColourImpl( IStream* stream ): ColourImpl( stream ) {}
3446
3447 private:
3448 void use( Colour::Code ) const override {}
3449 };
3450 } // namespace
3451
3452
3453} // namespace Catch
3454
3455
3456#if defined ( CATCH_CONFIG_COLOUR_WIN32 ) /////////////////////////////////////////
3457
3458namespace Catch {
3459namespace {
3460
3461 class Win32ColourImpl final : public ColourImpl {
3462 public:
3463 Win32ColourImpl(IStream* stream):
3464 ColourImpl(stream) {
3465 CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
3466 GetConsoleScreenBufferInfo( GetStdHandle( STD_OUTPUT_HANDLE ),
3467 &csbiInfo );
3468 originalForegroundAttributes = csbiInfo.wAttributes & ~( BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY );
3469 originalBackgroundAttributes = csbiInfo.wAttributes & ~( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY );
3470 }
3471
3472 static bool useImplementationForStream(IStream const& stream) {
3473 // Win32 text colour APIs can only be used on console streams
3474 // We cannot check that the output hasn't been redirected,
3475 // so we just check that the original stream is console stream.
3476 return stream.isConsole();
3477 }
3478
3479 private:
3480 void use( Colour::Code _colourCode ) const override {
3481 switch( _colourCode ) {
3482 case Colour::None: return setTextAttribute( originalForegroundAttributes );
3483 case Colour::White: return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3484 case Colour::Red: return setTextAttribute( FOREGROUND_RED );
3485 case Colour::Green: return setTextAttribute( FOREGROUND_GREEN );
3486 case Colour::Blue: return setTextAttribute( FOREGROUND_BLUE );
3487 case Colour::Cyan: return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
3488 case Colour::Yellow: return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
3489 case Colour::Grey: return setTextAttribute( 0 );
3490
3491 case Colour::LightGrey: return setTextAttribute( FOREGROUND_INTENSITY );
3492 case Colour::BrightRed: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
3493 case Colour::BrightGreen: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
3494 case Colour::BrightWhite: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
3495 case Colour::BrightYellow: return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED | FOREGROUND_GREEN );
3496
3497 case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3498
3499 default:
3500 CATCH_ERROR( "Unknown colour requested" );
3501 }
3502 }
3503
3504 void setTextAttribute( WORD _textAttribute ) const {
3505 SetConsoleTextAttribute( GetStdHandle( STD_OUTPUT_HANDLE ),
3506 _textAttribute |
3507 originalBackgroundAttributes );
3508 }
3509 WORD originalForegroundAttributes;
3510 WORD originalBackgroundAttributes;
3511 };
3512
3513} // end anon namespace
3514} // end namespace Catch
3515
3516#endif // Windows/ ANSI/ None
3517
3518
3519#if defined( CATCH_PLATFORM_LINUX ) || defined( CATCH_PLATFORM_MAC )
3520# define CATCH_INTERNAL_HAS_ISATTY
3521# include <unistd.h>
3522#endif
3523
3524namespace Catch {
3525namespace {
3526
3527 class ANSIColourImpl final : public ColourImpl {
3528 public:
3529 ANSIColourImpl( IStream* stream ): ColourImpl( stream ) {}
3530
3531 static bool useImplementationForStream(IStream const& stream) {
3532 // This is kinda messy due to trying to support a bunch of
3533 // different platforms at once.
3534 // The basic idea is that if we are asked to do autodetection (as
3535 // opposed to being told to use posixy colours outright), then we
3536 // only want to use the colours if we are writing to console.
3537 // However, console might be redirected, so we make an attempt at
3538 // checking for that on platforms where we know how to do that.
3539 bool useColour = stream.isConsole();
3540#if defined( CATCH_INTERNAL_HAS_ISATTY ) && \
3541 !( defined( __DJGPP__ ) && defined( __STRICT_ANSI__ ) )
3542 ErrnoGuard _; // for isatty
3543 useColour = useColour && isatty( STDOUT_FILENO );
3544# endif
3545# if defined( CATCH_PLATFORM_MAC ) || defined( CATCH_PLATFORM_IPHONE )
3546 useColour = useColour && !isDebuggerActive();
3547# endif
3548
3549 return useColour;
3550 }
3551
3552 private:
3553 void use( Colour::Code _colourCode ) const override {
3554 auto setColour = [&out =
3555 m_stream->stream()]( char const* escapeCode ) {
3556 // The escape sequence must be flushed to console, otherwise
3557 // if stdin and stderr are intermixed, we'd get accidentally
3558 // coloured output.
3559 out << '\033' << escapeCode << std::flush;
3560 };
3561 switch( _colourCode ) {
3562 case Colour::None:
3563 case Colour::White: return setColour( "[0m" );
3564 case Colour::Red: return setColour( "[0;31m" );
3565 case Colour::Green: return setColour( "[0;32m" );
3566 case Colour::Blue: return setColour( "[0;34m" );
3567 case Colour::Cyan: return setColour( "[0;36m" );
3568 case Colour::Yellow: return setColour( "[0;33m" );
3569 case Colour::Grey: return setColour( "[1;30m" );
3570
3571 case Colour::LightGrey: return setColour( "[0;37m" );
3572 case Colour::BrightRed: return setColour( "[1;31m" );
3573 case Colour::BrightGreen: return setColour( "[1;32m" );
3574 case Colour::BrightWhite: return setColour( "[1;37m" );
3575 case Colour::BrightYellow: return setColour( "[1;33m" );
3576
3577 case Colour::Bright: CATCH_INTERNAL_ERROR( "not a colour" );
3578 default: CATCH_INTERNAL_ERROR( "Unknown colour requested" );
3579 }
3580 }
3581 };
3582
3583} // end anon namespace
3584} // end namespace Catch
3585
3586namespace Catch {
3587
3588 Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
3589 IStream* stream ) {
3590#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3591 if ( colourSelection == ColourMode::Win32 ) {
3592 return Detail::make_unique<Win32ColourImpl>( stream );
3593 }
3594#endif
3595 if ( colourSelection == ColourMode::ANSI ) {
3596 return Detail::make_unique<ANSIColourImpl>( stream );
3597 }
3598 if ( colourSelection == ColourMode::None ) {
3599 return Detail::make_unique<NoColourImpl>( stream );
3600 }
3601
3602 if ( colourSelection == ColourMode::PlatformDefault) {
3603#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3604 if ( Win32ColourImpl::useImplementationForStream( *stream ) ) {
3605 return Detail::make_unique<Win32ColourImpl>( stream );
3606 }
3607#endif
3608 if ( ANSIColourImpl::useImplementationForStream( *stream ) ) {
3609 return Detail::make_unique<ANSIColourImpl>( stream );
3610 }
3611 return Detail::make_unique<NoColourImpl>( stream );
3612 }
3613
3614 CATCH_ERROR( "Could not create colour impl for selection " << static_cast<int>(colourSelection) );
3615 }
3616
3617 bool isColourImplAvailable( ColourMode colourSelection ) {
3618 switch ( colourSelection ) {
3619#if defined( CATCH_CONFIG_COLOUR_WIN32 )
3620 case ColourMode::Win32:
3621#endif
3622 case ColourMode::ANSI:
3623 case ColourMode::None:
3624 case ColourMode::PlatformDefault:
3625 return true;
3626 default:
3627 return false;
3628 }
3629 }
3630
3631
3632} // end namespace Catch
3633
3634#if defined(__clang__)
3635# pragma clang diagnostic pop
3636#endif
3637
3638
3639
3640
3641namespace Catch {
3642
3643 Context* Context::currentContext = nullptr;
3644
3645 void cleanUpContext() {
3646 delete Context::currentContext;
3647 Context::currentContext = nullptr;
3648 }
3649 void Context::createContext() {
3650 currentContext = new Context();
3651 }
3652
3653 Context& getCurrentMutableContext() {
3654 if ( !Context::currentContext ) { Context::createContext(); }
3655 // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
3656 return *Context::currentContext;
3657 }
3658
3659 SimplePcg32& sharedRng() {
3660 static SimplePcg32 s_rng;
3661 return s_rng;
3662 }
3663
3664}
3665
3666
3667
3668
3669
3670#include <ostream>
3671
3672#if defined(CATCH_CONFIG_ANDROID_LOGWRITE)
3673#include <android/log.h>
3674
3675 namespace Catch {
3676 void writeToDebugConsole( std::string const& text ) {
3677 __android_log_write( ANDROID_LOG_DEBUG, "Catch", text.c_str() );
3678 }
3679 }
3680
3681#elif defined(CATCH_PLATFORM_WINDOWS)
3682
3683 namespace Catch {
3684 void writeToDebugConsole( std::string const& text ) {
3685 ::OutputDebugStringA( text.c_str() );
3686 }
3687 }
3688
3689#else
3690
3691 namespace Catch {
3692 void writeToDebugConsole( std::string const& text ) {
3693 // !TBD: Need a version for Mac/ XCode and other IDEs
3694 Catch::cout() << text;
3695 }
3696 }
3697
3698#endif // Platform
3699
3700
3701
3702#if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE)
3703
3704# include <cassert>
3705# include <sys/types.h>
3706# include <unistd.h>
3707# include <cstddef>
3708# include <ostream>
3709
3710#ifdef __apple_build_version__
3711 // These headers will only compile with AppleClang (XCode)
3712 // For other compilers (Clang, GCC, ... ) we need to exclude them
3713# include <sys/sysctl.h>
3714#endif
3715
3716 namespace Catch {
3717 #ifdef __apple_build_version__
3718 // The following function is taken directly from the following technical note:
3719 // https://developer.apple.com/library/archive/qa/qa1361/_index.html
3720
3721 // Returns true if the current process is being debugged (either
3722 // running under the debugger or has a debugger attached post facto).
3723 bool isDebuggerActive(){
3724 int mib[4];
3725 struct kinfo_proc info;
3726 std::size_t size;
3727
3728 // Initialize the flags so that, if sysctl fails for some bizarre
3729 // reason, we get a predictable result.
3730
3731 info.kp_proc.p_flag = 0;
3732
3733 // Initialize mib, which tells sysctl the info we want, in this case
3734 // we're looking for information about a specific process ID.
3735
3736 mib[0] = CTL_KERN;
3737 mib[1] = KERN_PROC;
3738 mib[2] = KERN_PROC_PID;
3739 mib[3] = getpid();
3740
3741 // Call sysctl.
3742
3743 size = sizeof(info);
3744 if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, nullptr, 0) != 0 ) {
3745 Catch::cerr() << "\n** Call to sysctl failed - unable to determine if debugger is active **\n\n" << std::flush;
3746 return false;
3747 }
3748
3749 // We're being debugged if the P_TRACED flag is set.
3750
3751 return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
3752 }
3753 #else
3754 bool isDebuggerActive() {
3755 // We need to find another way to determine this for non-appleclang compilers on macOS
3756 return false;
3757 }
3758 #endif
3759 } // namespace Catch
3760
3761#elif defined(CATCH_PLATFORM_LINUX)
3762 #include <fstream>
3763 #include <string>
3764
3765 namespace Catch{
3766 // The standard POSIX way of detecting a debugger is to attempt to
3767 // ptrace() the process, but this needs to be done from a child and not
3768 // this process itself to still allow attaching to this process later
3769 // if wanted, so is rather heavy. Under Linux we have the PID of the
3770 // "debugger" (which doesn't need to be gdb, of course, it could also
3771 // be strace, for example) in /proc/$PID/status, so just get it from
3772 // there instead.
3773 bool isDebuggerActive(){
3774 // Libstdc++ has a bug, where std::ifstream sets errno to 0
3775 // This way our users can properly assert over errno values
3776 ErrnoGuard guard;
3777 std::ifstream in("/proc/self/status");
3778 for( std::string line; std::getline(in, line); ) {
3779 static const int PREFIX_LEN = 11;
3780 if( line.compare(0, PREFIX_LEN, "TracerPid:\t") == 0 ) {
3781 // We're traced if the PID is not 0 and no other PID starts
3782 // with 0 digit, so it's enough to check for just a single
3783 // character.
3784 return line.length() > PREFIX_LEN && line[PREFIX_LEN] != '0';
3785 }
3786 }
3787
3788 return false;
3789 }
3790 } // namespace Catch
3791#elif defined(_MSC_VER)
3792 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3793 namespace Catch {
3794 bool isDebuggerActive() {
3795 return IsDebuggerPresent() != 0;
3796 }
3797 }
3798#elif defined(__MINGW32__)
3799 extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
3800 namespace Catch {
3801 bool isDebuggerActive() {
3802 return IsDebuggerPresent() != 0;
3803 }
3804 }
3805#else
3806 namespace Catch {
3807 bool isDebuggerActive() { return false; }
3808 }
3809#endif // Platform
3810
3811
3812
3813
3814namespace Catch {
3815
3816 void ITransientExpression::streamReconstructedExpression(
3817 std::ostream& os ) const {
3818 // We can't make this function pure virtual to keep ITransientExpression
3819 // constexpr, so we write error message instead
3820 os << "Some class derived from ITransientExpression without overriding streamReconstructedExpression";
3821 }
3822
3823 void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs ) {
3824 if( lhs.size() + rhs.size() < 40 &&
3825 lhs.find('\n') == std::string::npos &&
3826 rhs.find('\n') == std::string::npos )
3827 os << lhs << ' ' << op << ' ' << rhs;
3828 else
3829 os << lhs << '\n' << op << '\n' << rhs;
3830 }
3831}
3832
3833
3834
3835#include <stdexcept>
3836
3837
3838namespace Catch {
3839#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS_CUSTOM_HANDLER)
3840 [[noreturn]]
3841 void throw_exception(std::exception const& e) {
3842 Catch::cerr() << "Catch will terminate because it needed to throw an exception.\n"
3843 << "The message was: " << e.what() << '\n';
3844 std::terminate();
3845 }
3846#endif
3847
3848 [[noreturn]]
3849 void throw_logic_error(std::string const& msg) {
3850 throw_exception(std::logic_error(msg));
3851 }
3852
3853 [[noreturn]]
3854 void throw_domain_error(std::string const& msg) {
3855 throw_exception(std::domain_error(msg));
3856 }
3857
3858 [[noreturn]]
3859 void throw_runtime_error(std::string const& msg) {
3860 throw_exception(std::runtime_error(msg));
3861 }
3862
3863
3864
3865} // namespace Catch;
3866
3867
3868
3869#include <cassert>
3870
3871namespace Catch {
3872
3873 IMutableEnumValuesRegistry::~IMutableEnumValuesRegistry() = default;
3874
3875 namespace Detail {
3876
3877 namespace {
3878 // Extracts the actual name part of an enum instance
3879 // In other words, it returns the Blue part of Bikeshed::Colour::Blue
3880 StringRef extractInstanceName(StringRef enumInstance) {
3881 // Find last occurrence of ":"
3882 size_t name_start = enumInstance.size();
3883 while (name_start > 0 && enumInstance[name_start - 1] != ':') {
3884 --name_start;
3885 }
3886 return enumInstance.substr(name_start, enumInstance.size() - name_start);
3887 }
3888 }
3889
3890 std::vector<StringRef> parseEnums( StringRef enums ) {
3891 auto enumValues = splitStringRef( enums, ',' );
3892 std::vector<StringRef> parsed;
3893 parsed.reserve( enumValues.size() );
3894 for( auto const& enumValue : enumValues ) {
3895 parsed.push_back(trim(extractInstanceName(enumValue)));
3896 }
3897 return parsed;
3898 }
3899
3900 EnumInfo::~EnumInfo() = default;
3901
3902 StringRef EnumInfo::lookup( int value ) const {
3903 for( auto const& valueToName : m_values ) {
3904 if( valueToName.first == value )
3905 return valueToName.second;
3906 }
3907 return "{** unexpected enum value **}"_sr;
3908 }
3909
3910 Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
3911 auto enumInfo = Catch::Detail::make_unique<EnumInfo>();
3912 enumInfo->m_name = enumName;
3913 enumInfo->m_values.reserve( values.size() );
3914
3915 const auto valueNames = Catch::Detail::parseEnums( allValueNames );
3916 assert( valueNames.size() == values.size() );
3917 std::size_t i = 0;
3918 for( auto value : values )
3919 enumInfo->m_values.emplace_back(value, valueNames[i++]);
3920
3921 return enumInfo;
3922 }
3923
3924 EnumInfo const& EnumValuesRegistry::registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values ) {
3925 m_enumInfos.push_back(makeEnumInfo(enumName, allValueNames, values));
3926 return *m_enumInfos.back();
3927 }
3928
3929 } // Detail
3930} // Catch
3931
3932
3933
3934
3935
3936#include <cerrno>
3937
3938namespace Catch {
3939 ErrnoGuard::ErrnoGuard():m_oldErrno(errno){}
3940 ErrnoGuard::~ErrnoGuard() { errno = m_oldErrno; }
3941}
3942
3943
3944
3945#include <exception>
3946
3947namespace Catch {
3948
3949#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
3950 namespace {
3951 static std::string tryTranslators(
3952 std::vector<
3953 Detail::unique_ptr<IExceptionTranslator const>> const& translators ) {
3954 if ( translators.empty() ) {
3955 std::rethrow_exception( std::current_exception() );
3956 } else {
3957 return translators[0]->translate( translators.begin() + 1,
3958 translators.end() );
3959 }
3960 }
3961
3962 }
3963#endif //!defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
3964
3965 ExceptionTranslatorRegistry::~ExceptionTranslatorRegistry() = default;
3966
3967 void ExceptionTranslatorRegistry::registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) {
3968 m_translators.push_back( CATCH_MOVE( translator ) );
3969 }
3970
3971#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
3972 std::string ExceptionTranslatorRegistry::translateActiveException() const {
3973 // Compiling a mixed mode project with MSVC means that CLR
3974 // exceptions will be caught in (...) as well. However, these do
3975 // do not fill-in std::current_exception and thus lead to crash
3976 // when attempting rethrow.
3977 // /EHa switch also causes structured exceptions to be caught
3978 // here, but they fill-in current_exception properly, so
3979 // at worst the output should be a little weird, instead of
3980 // causing a crash.
3981 if ( std::current_exception() == nullptr ) {
3982 return "Non C++ exception. Possibly a CLR exception.";
3983 }
3984
3985 // First we try user-registered translators. If none of them can
3986 // handle the exception, it will be rethrown handled by our defaults.
3987 try {
3988 return tryTranslators(m_translators);
3989 }
3990 // To avoid having to handle TFE explicitly everywhere, we just
3991 // rethrow it so that it goes back up the caller.
3992 catch( TestFailureException& ) {
3993 std::rethrow_exception(std::current_exception());
3994 }
3995 catch( TestSkipException& ) {
3996 std::rethrow_exception(std::current_exception());
3997 }
3998 catch( std::exception const& ex ) {
3999 return ex.what();
4000 }
4001 catch( std::string const& msg ) {
4002 return msg;
4003 }
4004 catch( const char* msg ) {
4005 return msg;
4006 }
4007 catch(...) {
4008 return "Unknown exception";
4009 }
4010 }
4011
4012#else // ^^ Exceptions are enabled // Exceptions are disabled vv
4013 std::string ExceptionTranslatorRegistry::translateActiveException() const {
4014 CATCH_INTERNAL_ERROR("Attempted to translate active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!");
4015 }
4016#endif
4017
4018}
4019
4020
4021
4022/** \file
4023 * This file provides platform specific implementations of FatalConditionHandler
4024 *
4025 * This means that there is a lot of conditional compilation, and platform
4026 * specific code. Currently, Catch2 supports a dummy handler (if no
4027 * handler is desired), and 2 platform specific handlers:
4028 * * Windows' SEH
4029 * * POSIX signals
4030 *
4031 * Consequently, various pieces of code below are compiled if either of
4032 * the platform specific handlers is enabled, or if none of them are
4033 * enabled. It is assumed that both cannot be enabled at the same time,
4034 * and doing so should cause a compilation error.
4035 *
4036 * If another platform specific handler is added, the compile guards
4037 * below will need to be updated taking these assumptions into account.
4038 */
4039
4040
4041
4042#include <algorithm>
4043
4044#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS )
4045
4046namespace Catch {
4047
4048 // If neither SEH nor signal handling is required, the handler impls
4049 // do not have to do anything, and can be empty.
4050 void FatalConditionHandler::engage_platform() {}
4051 void FatalConditionHandler::disengage_platform() noexcept {}
4052 FatalConditionHandler::FatalConditionHandler() = default;
4053 FatalConditionHandler::~FatalConditionHandler() = default;
4054
4055} // end namespace Catch
4056
4057#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS
4058
4059#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS )
4060#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time"
4061#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS
4062
4063#if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS )
4064
4065namespace {
4066 //! Signals fatal error message to the run context
4067 void reportFatal( char const * const message ) {
4068 Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message );
4069 }
4070
4071 //! Minimal size Catch2 needs for its own fatal error handling.
4072 //! Picked empirically, so it might not be sufficient on all
4073 //! platforms, and for all configurations.
4074 constexpr std::size_t minStackSizeForErrors = 32 * 1024;
4075} // end unnamed namespace
4076
4077#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS
4078
4079#if defined( CATCH_CONFIG_WINDOWS_SEH )
4080
4081namespace Catch {
4082
4083 struct SignalDefs { DWORD id; const char* name; };
4084
4085 // There is no 1-1 mapping between signals and windows exceptions.
4086 // Windows can easily distinguish between SO and SigSegV,
4087 // but SigInt, SigTerm, etc are handled differently.
4088 static SignalDefs signalDefs[] = {
4089 { EXCEPTION_ILLEGAL_INSTRUCTION, "SIGILL - Illegal instruction signal" },
4090 { EXCEPTION_STACK_OVERFLOW, "SIGSEGV - Stack overflow" },
4091 { EXCEPTION_ACCESS_VIOLATION, "SIGSEGV - Segmentation violation signal" },
4092 { EXCEPTION_INT_DIVIDE_BY_ZERO, "Divide by zero error" },
4093 };
4094
4095 static LONG CALLBACK topLevelExceptionFilter(PEXCEPTION_POINTERS ExceptionInfo) {
4096 for (auto const& def : signalDefs) {
4097 if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) {
4098 reportFatal(def.name);
4099 }
4100 }
4101 // If its not an exception we care about, pass it along.
4102 // This stops us from eating debugger breaks etc.
4103 return EXCEPTION_CONTINUE_SEARCH;
4104 }
4105
4106 // Since we do not support multiple instantiations, we put these
4107 // into global variables and rely on cleaning them up in outlined
4108 // constructors/destructors
4109 static LPTOP_LEVEL_EXCEPTION_FILTER previousTopLevelExceptionFilter = nullptr;
4110
4111
4112 // For MSVC, we reserve part of the stack memory for handling
4113 // memory overflow structured exception.
4114 FatalConditionHandler::FatalConditionHandler() {
4115 ULONG guaranteeSize = static_cast<ULONG>(minStackSizeForErrors);
4116 if (!SetThreadStackGuarantee(&guaranteeSize)) {
4117 // We do not want to fully error out, because needing
4118 // the stack reserve should be rare enough anyway.
4119 Catch::cerr()
4120 << "Failed to reserve piece of stack."
4121 << " Stack overflows will not be reported successfully.";
4122 }
4123 }
4124
4125 // We do not attempt to unset the stack guarantee, because
4126 // Windows does not support lowering the stack size guarantee.
4127 FatalConditionHandler::~FatalConditionHandler() = default;
4128
4129
4130 void FatalConditionHandler::engage_platform() {
4131 // Register as a the top level exception filter.
4132 previousTopLevelExceptionFilter = SetUnhandledExceptionFilter(topLevelExceptionFilter);
4133 }
4134
4135 void FatalConditionHandler::disengage_platform() noexcept {
4136 if (SetUnhandledExceptionFilter(previousTopLevelExceptionFilter) != topLevelExceptionFilter) {
4137 Catch::cerr()
4138 << "Unexpected SEH unhandled exception filter on disengage."
4139 << " The filter was restored, but might be rolled back unexpectedly.";
4140 }
4141 previousTopLevelExceptionFilter = nullptr;
4142 }
4143
4144} // end namespace Catch
4145
4146#endif // CATCH_CONFIG_WINDOWS_SEH
4147
4148#if defined( CATCH_CONFIG_POSIX_SIGNALS )
4149
4150#include <signal.h>
4151
4152namespace Catch {
4153
4154 struct SignalDefs {
4155 int id;
4156 const char* name;
4157 };
4158
4159 static SignalDefs signalDefs[] = {
4160 { SIGINT, "SIGINT - Terminal interrupt signal" },
4161 { SIGILL, "SIGILL - Illegal instruction signal" },
4162 { SIGFPE, "SIGFPE - Floating point error signal" },
4163 { SIGSEGV, "SIGSEGV - Segmentation violation signal" },
4164 { SIGTERM, "SIGTERM - Termination request signal" },
4165 { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" }
4166 };
4167
4168// Older GCCs trigger -Wmissing-field-initializers for T foo = {}
4169// which is zero initialization, but not explicit. We want to avoid
4170// that.
4171#if defined(__GNUC__)
4172# pragma GCC diagnostic push
4173# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
4174#endif
4175
4176 static char* altStackMem = nullptr;
4177 static std::size_t altStackSize = 0;
4178 static stack_t oldSigStack{};
4179 static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{};
4180
4181 static void restorePreviousSignalHandlers() noexcept {
4182 // We set signal handlers back to the previous ones. Hopefully
4183 // nobody overwrote them in the meantime, and doesn't expect
4184 // their signal handlers to live past ours given that they
4185 // installed them after ours..
4186 for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) {
4187 sigaction(signalDefs[i].id, &oldSigActions[i], nullptr);
4188 }
4189 // Return the old stack
4190 sigaltstack(&oldSigStack, nullptr);
4191 }
4192
4193 static void handleSignal( int sig ) {
4194 char const * name = "<unknown signal>";
4195 for (auto const& def : signalDefs) {
4196 if (sig == def.id) {
4197 name = def.name;
4198 break;
4199 }
4200 }
4201 // We need to restore previous signal handlers and let them do
4202 // their thing, so that the users can have the debugger break
4203 // when a signal is raised, and so on.
4204 restorePreviousSignalHandlers();
4205 reportFatal( name );
4206 raise( sig );
4207 }
4208
4209 FatalConditionHandler::FatalConditionHandler() {
4210 assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists");
4211 if (altStackSize == 0) {
4212 altStackSize = std::max(static_cast<size_t>(SIGSTKSZ), minStackSizeForErrors);
4213 }
4214 altStackMem = new char[altStackSize]();
4215 }
4216
4217 FatalConditionHandler::~FatalConditionHandler() {
4218 delete[] altStackMem;
4219 // We signal that another instance can be constructed by zeroing
4220 // out the pointer.
4221 altStackMem = nullptr;
4222 }
4223
4224 void FatalConditionHandler::engage_platform() {
4225 stack_t sigStack;
4226 sigStack.ss_sp = altStackMem;
4227 sigStack.ss_size = altStackSize;
4228 sigStack.ss_flags = 0;
4229 sigaltstack(&sigStack, &oldSigStack);
4230 struct sigaction sa = { };
4231
4232 sa.sa_handler = handleSignal;
4233 sa.sa_flags = SA_ONSTACK;
4234 for (std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i) {
4235 sigaction(signalDefs[i].id, &sa, &oldSigActions[i]);
4236 }
4237 }
4238
4239#if defined(__GNUC__)
4240# pragma GCC diagnostic pop
4241#endif
4242
4243
4244 void FatalConditionHandler::disengage_platform() noexcept {
4245 restorePreviousSignalHandlers();
4246 }
4247
4248} // end namespace Catch
4249
4250#endif // CATCH_CONFIG_POSIX_SIGNALS
4251
4252
4253
4254
4255#include <cstring>
4256
4257namespace Catch {
4258 namespace Detail {
4259
4260 uint32_t convertToBits(float f) {
4261 static_assert(sizeof(float) == sizeof(uint32_t), "Important ULP matcher assumption violated");
4262 uint32_t i;
4263 std::memcpy(&i, &f, sizeof(f));
4264 return i;
4265 }
4266
4267 uint64_t convertToBits(double d) {
4268 static_assert(sizeof(double) == sizeof(uint64_t), "Important ULP matcher assumption violated");
4269 uint64_t i;
4270 std::memcpy(&i, &d, sizeof(d));
4271 return i;
4272 }
4273
4274#if defined( __GNUC__ ) || defined( __clang__ )
4275# pragma GCC diagnostic push
4276# pragma GCC diagnostic ignored "-Wfloat-equal"
4277#endif
4278 bool directCompare( float lhs, float rhs ) { return lhs == rhs; }
4279 bool directCompare( double lhs, double rhs ) { return lhs == rhs; }
4280#if defined( __GNUC__ ) || defined( __clang__ )
4281# pragma GCC diagnostic pop
4282#endif
4283
4284
4285 } // end namespace Detail
4286} // end namespace Catch
4287
4288
4289
4290
4291
4292
4293#include <cstdlib>
4294
4295namespace Catch {
4296 namespace Detail {
4297
4298#if !defined (CATCH_CONFIG_GETENV)
4299 char const* getEnv( char const* ) { return nullptr; }
4300#else
4301
4302 char const* getEnv( char const* varName ) {
4303# if defined( _MSC_VER )
4304# pragma warning( push )
4305# pragma warning( disable : 4996 ) // use getenv_s instead of getenv
4306# endif
4307
4308 return std::getenv( varName );
4309
4310# if defined( _MSC_VER )
4311# pragma warning( pop )
4312# endif
4313 }
4314#endif
4315} // namespace Detail
4316} // namespace Catch
4317
4318
4319
4320
4321#include <cstdio>
4322#include <fstream>
4323#include <sstream>
4324#include <vector>
4325
4326namespace Catch {
4327
4328 Catch::IStream::~IStream() = default;
4329
4330namespace Detail {
4331 namespace {
4332 template<typename WriterF, std::size_t bufferSize=256>
4333 class StreamBufImpl final : public std::streambuf {
4334 char data[bufferSize];
4335 WriterF m_writer;
4336
4337 public:
4338 StreamBufImpl() {
4339 setp( data, data + sizeof(data) );
4340 }
4341
4342 ~StreamBufImpl() noexcept override {
4343 StreamBufImpl::sync();
4344 }
4345
4346 private:
4347 int overflow( int c ) override {
4348 sync();
4349
4350 if( c != EOF ) {
4351 if( pbase() == epptr() )
4352 m_writer( std::string( 1, static_cast<char>( c ) ) );
4353 else
4354 sputc( static_cast<char>( c ) );
4355 }
4356 return 0;
4357 }
4358
4359 int sync() override {
4360 if( pbase() != pptr() ) {
4361 m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
4362 setp( pbase(), epptr() );
4363 }
4364 return 0;
4365 }
4366 };
4367
4368 ///////////////////////////////////////////////////////////////////////////
4369
4370 struct OutputDebugWriter {
4371
4372 void operator()( std::string const& str ) {
4373 if ( !str.empty() ) {
4374 writeToDebugConsole( str );
4375 }
4376 }
4377 };
4378
4379 ///////////////////////////////////////////////////////////////////////////
4380
4381 class FileStream final : public IStream {
4382 std::ofstream m_ofs;
4383 public:
4384 FileStream( std::string const& filename ) {
4385 m_ofs.open( filename.c_str() );
4386 CATCH_ENFORCE( !m_ofs.fail(), "Unable to open file: '" << filename << '\'' );
4387 m_ofs << std::unitbuf;
4388 }
4389 public: // IStream
4390 std::ostream& stream() override {
4391 return m_ofs;
4392 }
4393 };
4394
4395 ///////////////////////////////////////////////////////////////////////////
4396
4397 class CoutStream final : public IStream {
4398 std::ostream m_os;
4399 public:
4400 // Store the streambuf from cout up-front because
4401 // cout may get redirected when running tests
4402 CoutStream() : m_os( Catch::cout().rdbuf() ) {}
4403
4404 public: // IStream
4405 std::ostream& stream() override { return m_os; }
4406 bool isConsole() const override { return true; }
4407 };
4408
4409 class CerrStream : public IStream {
4410 std::ostream m_os;
4411
4412 public:
4413 // Store the streambuf from cerr up-front because
4414 // cout may get redirected when running tests
4415 CerrStream(): m_os( Catch::cerr().rdbuf() ) {}
4416
4417 public: // IStream
4418 std::ostream& stream() override { return m_os; }
4419 bool isConsole() const override { return true; }
4420 };
4421
4422 ///////////////////////////////////////////////////////////////////////////
4423
4424 class DebugOutStream final : public IStream {
4425 Detail::unique_ptr<StreamBufImpl<OutputDebugWriter>> m_streamBuf;
4426 std::ostream m_os;
4427 public:
4428 DebugOutStream()
4429 : m_streamBuf( Detail::make_unique<StreamBufImpl<OutputDebugWriter>>() ),
4430 m_os( m_streamBuf.get() )
4431 {}
4432
4433 public: // IStream
4434 std::ostream& stream() override { return m_os; }
4435 };
4436
4437 } // unnamed namespace
4438} // namespace Detail
4439
4440 ///////////////////////////////////////////////////////////////////////////
4441
4442 auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream> {
4443 if ( filename.empty() || filename == "-" ) {
4444 return Detail::make_unique<Detail::CoutStream>();
4445 }
4446 if( filename[0] == '%' ) {
4447 if ( filename == "%debug" ) {
4448 return Detail::make_unique<Detail::DebugOutStream>();
4449 } else if ( filename == "%stderr" ) {
4450 return Detail::make_unique<Detail::CerrStream>();
4451 } else if ( filename == "%stdout" ) {
4452 return Detail::make_unique<Detail::CoutStream>();
4453 } else {
4454 CATCH_ERROR( "Unrecognised stream: '" << filename << '\'' );
4455 }
4456 }
4457 return Detail::make_unique<Detail::FileStream>( filename );
4458 }
4459
4460}
4461
4462
4463
4464namespace Catch {
4465 void JsonUtils::indent( std::ostream& os, std::uint64_t level ) {
4466 for ( std::uint64_t i = 0; i < level; ++i ) {
4467 os << " ";
4468 }
4469 }
4470 void JsonUtils::appendCommaNewline( std::ostream& os,
4471 bool& should_comma,
4472 std::uint64_t level ) {
4473 if ( should_comma ) { os << ','; }
4474 should_comma = true;
4475 os << '\n';
4476 indent( os, level );
4477 }
4478
4479 JsonObjectWriter::JsonObjectWriter( std::ostream& os ):
4480 JsonObjectWriter{ os, 0 } {}
4481
4482 JsonObjectWriter::JsonObjectWriter( std::ostream& os,
4483 std::uint64_t indent_level ):
4484 m_os{ os }, m_indent_level{ indent_level } {
4485 m_os << '{';
4486 }
4487 JsonObjectWriter::JsonObjectWriter( JsonObjectWriter&& source ) noexcept:
4488 m_os{ source.m_os },
4489 m_indent_level{ source.m_indent_level },
4490 m_should_comma{ source.m_should_comma },
4491 m_active{ source.m_active } {
4492 source.m_active = false;
4493 }
4494
4495 JsonObjectWriter::~JsonObjectWriter() {
4496 if ( !m_active ) { return; }
4497
4498 m_os << '\n';
4499 JsonUtils::indent( m_os, m_indent_level );
4500 m_os << '}';
4501 }
4502
4503 JsonValueWriter JsonObjectWriter::write( StringRef key ) {
4504 JsonUtils::appendCommaNewline(
4505 m_os, m_should_comma, m_indent_level + 1 );
4506
4507 m_os << '"' << key << "\": ";
4508 return JsonValueWriter{ m_os, m_indent_level + 1 };
4509 }
4510
4511 JsonArrayWriter::JsonArrayWriter( std::ostream& os ):
4512 JsonArrayWriter{ os, 0 } {}
4513 JsonArrayWriter::JsonArrayWriter( std::ostream& os,
4514 std::uint64_t indent_level ):
4515 m_os{ os }, m_indent_level{ indent_level } {
4516 m_os << '[';
4517 }
4518 JsonArrayWriter::JsonArrayWriter( JsonArrayWriter&& source ) noexcept:
4519 m_os{ source.m_os },
4520 m_indent_level{ source.m_indent_level },
4521 m_should_comma{ source.m_should_comma },
4522 m_active{ source.m_active } {
4523 source.m_active = false;
4524 }
4525 JsonArrayWriter::~JsonArrayWriter() {
4526 if ( !m_active ) { return; }
4527
4528 m_os << '\n';
4529 JsonUtils::indent( m_os, m_indent_level );
4530 m_os << ']';
4531 }
4532
4533 JsonObjectWriter JsonArrayWriter::writeObject() {
4534 JsonUtils::appendCommaNewline(
4535 m_os, m_should_comma, m_indent_level + 1 );
4536 return JsonObjectWriter{ m_os, m_indent_level + 1 };
4537 }
4538
4539 JsonArrayWriter JsonArrayWriter::writeArray() {
4540 JsonUtils::appendCommaNewline(
4541 m_os, m_should_comma, m_indent_level + 1 );
4542 return JsonArrayWriter{ m_os, m_indent_level + 1 };
4543 }
4544
4545 JsonArrayWriter& JsonArrayWriter::write( bool value ) {
4546 return writeImpl( value );
4547 }
4548
4549 JsonValueWriter::JsonValueWriter( std::ostream& os ):
4550 JsonValueWriter{ os, 0 } {}
4551
4552 JsonValueWriter::JsonValueWriter( std::ostream& os,
4553 std::uint64_t indent_level ):
4554 m_os{ os }, m_indent_level{ indent_level } {}
4555
4556 JsonObjectWriter JsonValueWriter::writeObject() && {
4557 return JsonObjectWriter{ m_os, m_indent_level };
4558 }
4559
4560 JsonArrayWriter JsonValueWriter::writeArray() && {
4561 return JsonArrayWriter{ m_os, m_indent_level };
4562 }
4563
4564 void JsonValueWriter::write( Catch::StringRef value ) && {
4565 writeImpl( value, true );
4566 }
4567
4568 void JsonValueWriter::write( bool value ) && {
4569 writeImpl( value ? "true"_sr : "false"_sr, false );
4570 }
4571
4572 void JsonValueWriter::writeImpl( Catch::StringRef value, bool quote ) {
4573 if ( quote ) { m_os << '"'; }
4574 for (char c : value) {
4575 // Escape list taken from https://www.json.org/json-en.html,
4576 // string definition.
4577 // Note that while forward slash _can_ be escaped, it does
4578 // not have to be, if JSON is not further embedded somewhere
4579 // where forward slash is meaningful.
4580 if ( c == '"' ) {
4581 m_os << "\\\"";
4582 } else if ( c == '\\' ) {
4583 m_os << "\\\\";
4584 } else if ( c == '\b' ) {
4585 m_os << "\\b";
4586 } else if ( c == '\f' ) {
4587 m_os << "\\f";
4588 } else if ( c == '\n' ) {
4589 m_os << "\\n";
4590 } else if ( c == '\r' ) {
4591 m_os << "\\r";
4592 } else if ( c == '\t' ) {
4593 m_os << "\\t";
4594 } else {
4595 m_os << c;
4596 }
4597 }
4598 if ( quote ) { m_os << '"'; }
4599 }
4600
4601} // namespace Catch
4602
4603
4604
4605
4606namespace Catch {
4607
4608 auto operator << (std::ostream& os, LazyExpression const& lazyExpr) -> std::ostream& {
4609 if (lazyExpr.m_isNegated)
4610 os << '!';
4611
4612 if (lazyExpr) {
4613 if (lazyExpr.m_isNegated && lazyExpr.m_transientExpression->isBinaryExpression())
4614 os << '(' << *lazyExpr.m_transientExpression << ')';
4615 else
4616 os << *lazyExpr.m_transientExpression;
4617 } else {
4618 os << "{** error - unchecked empty expression requested **}";
4619 }
4620 return os;
4621 }
4622
4623} // namespace Catch
4624
4625
4626
4627
4628#ifdef CATCH_CONFIG_WINDOWS_CRTDBG
4629#include <crtdbg.h>
4630
4631namespace Catch {
4632
4633 LeakDetector::LeakDetector() {
4634 int flag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
4635 flag |= _CRTDBG_LEAK_CHECK_DF;
4636 flag |= _CRTDBG_ALLOC_MEM_DF;
4637 _CrtSetDbgFlag(flag);
4638 _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
4639 _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
4640 // Change this to leaking allocation's number to break there
4641 _CrtSetBreakAlloc(-1);
4642 }
4643}
4644
4645#else // ^^ Windows crt debug heap enabled // Windows crt debug heap disabled vv
4646
4647 Catch::LeakDetector::LeakDetector() = default;
4648
4649#endif // CATCH_CONFIG_WINDOWS_CRTDBG
4650
4651Catch::LeakDetector::~LeakDetector() {
4652 Catch::cleanUp();
4653}
4654
4655
4656
4657
4658namespace Catch {
4659 namespace {
4660
4661 void listTests(IEventListener& reporter, IConfig const& config) {
4662 auto const& testSpec = config.testSpec();
4663 auto matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4664 reporter.listTests(matchedTestCases);
4665 }
4666
4667 void listTags(IEventListener& reporter, IConfig const& config) {
4668 auto const& testSpec = config.testSpec();
4669 std::vector<TestCaseHandle> matchedTestCases = filterTests(getAllTestCasesSorted(config), testSpec, config);
4670
4671 std::map<StringRef, TagInfo, Detail::CaseInsensitiveLess> tagCounts;
4672 for (auto const& testCase : matchedTestCases) {
4673 for (auto const& tagName : testCase.getTestCaseInfo().tags) {
4674 auto it = tagCounts.find(tagName.original);
4675 if (it == tagCounts.end())
4676 it = tagCounts.insert(std::make_pair(tagName.original, TagInfo())).first;
4677 it->second.add(tagName.original);
4678 }
4679 }
4680
4681 std::vector<TagInfo> infos; infos.reserve(tagCounts.size());
4682 for (auto& tagc : tagCounts) {
4683 infos.push_back(CATCH_MOVE(tagc.second));
4684 }
4685
4686 reporter.listTags(infos);
4687 }
4688
4689 void listReporters(IEventListener& reporter) {
4690 std::vector<ReporterDescription> descriptions;
4691
4692 auto const& factories = getRegistryHub().getReporterRegistry().getFactories();
4693 descriptions.reserve(factories.size());
4694 for (auto const& fac : factories) {
4695 descriptions.push_back({ fac.first, fac.second->getDescription() });
4696 }
4697
4698 reporter.listReporters(descriptions);
4699 }
4700
4701 void listListeners(IEventListener& reporter) {
4702 std::vector<ListenerDescription> descriptions;
4703
4704 auto const& factories =
4705 getRegistryHub().getReporterRegistry().getListeners();
4706 descriptions.reserve( factories.size() );
4707 for ( auto const& fac : factories ) {
4708 descriptions.push_back( { fac->getName(), fac->getDescription() } );
4709 }
4710
4711 reporter.listListeners( descriptions );
4712 }
4713
4714 } // end anonymous namespace
4715
4716 void TagInfo::add( StringRef spelling ) {
4717 ++count;
4718 spellings.insert( spelling );
4719 }
4720
4721 std::string TagInfo::all() const {
4722 // 2 per tag for brackets '[' and ']'
4723 size_t size = spellings.size() * 2;
4724 for (auto const& spelling : spellings) {
4725 size += spelling.size();
4726 }
4727
4728 std::string out; out.reserve(size);
4729 for (auto const& spelling : spellings) {
4730 out += '[';
4731 out += spelling;
4732 out += ']';
4733 }
4734 return out;
4735 }
4736
4737 bool list( IEventListener& reporter, Config const& config ) {
4738 bool listed = false;
4739 if (config.listTests()) {
4740 listed = true;
4741 listTests(reporter, config);
4742 }
4743 if (config.listTags()) {
4744 listed = true;
4745 listTags(reporter, config);
4746 }
4747 if (config.listReporters()) {
4748 listed = true;
4749 listReporters(reporter);
4750 }
4751 if ( config.listListeners() ) {
4752 listed = true;
4753 listListeners( reporter );
4754 }
4755 return listed;
4756 }
4757
4758} // end namespace Catch
4759
4760
4761
4762namespace Catch {
4763 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
4764 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
4765 static LeakDetector leakDetector;
4766 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
4767}
4768
4769// Allow users of amalgamated .cpp file to remove our main and provide their own.
4770#if !defined(CATCH_AMALGAMATED_CUSTOM_MAIN)
4771
4772#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN)
4773// Standard C/C++ Win32 Unicode wmain entry point
4774extern "C" int __cdecl wmain (int argc, wchar_t * argv[], wchar_t * []) {
4775#else
4776// Standard C/C++ main entry point
4777int main (int argc, char * argv[]) {
4778#endif
4779
4780 // We want to force the linker not to discard the global variable
4781 // and its constructor, as it (optionally) registers leak detector
4782 (void)&Catch::leakDetector;
4783
4784 return Catch::Session().run( argc, argv );
4785}
4786
4787#endif // !defined(CATCH_AMALGAMATED_CUSTOM_MAIN
4788
4789
4790
4791
4792namespace Catch {
4793
4794 MessageInfo::MessageInfo( StringRef _macroName,
4795 SourceLineInfo const& _lineInfo,
4796 ResultWas::OfType _type )
4797 : macroName( _macroName ),
4798 lineInfo( _lineInfo ),
4799 type( _type ),
4800 sequence( ++globalCount )
4801 {}
4802
4803 // This may need protecting if threading support is added
4804 unsigned int MessageInfo::globalCount = 0;
4805
4806} // end namespace Catch
4807
4808
4809
4810#include <cstdio>
4811#include <cstring>
4812#include <iosfwd>
4813#include <sstream>
4814
4815#if defined( CATCH_CONFIG_NEW_CAPTURE )
4816# if defined( _MSC_VER )
4817# include <io.h> //_dup and _dup2
4818# define dup _dup
4819# define dup2 _dup2
4820# define fileno _fileno
4821# else
4822# include <unistd.h> // dup and dup2
4823# endif
4824#endif
4825
4826namespace Catch {
4827
4828 namespace {
4829 //! A no-op implementation, used if no reporter wants output
4830 //! redirection.
4831 class NoopRedirect : public OutputRedirect {
4832 void activateImpl() override {}
4833 void deactivateImpl() override {}
4834 std::string getStdout() override { return {}; }
4835 std::string getStderr() override { return {}; }
4836 void clearBuffers() override {}
4837 };
4838
4839 /**
4840 * Redirects specific stream's rdbuf with another's.
4841 *
4842 * Redirection can be stopped and started on-demand, assumes
4843 * that the underlying stream's rdbuf aren't changed by other
4844 * users.
4845 */
4846 class RedirectedStreamNew {
4847 std::ostream& m_originalStream;
4848 std::ostream& m_redirectionStream;
4849 std::streambuf* m_prevBuf;
4850
4851 public:
4852 RedirectedStreamNew( std::ostream& originalStream,
4853 std::ostream& redirectionStream ):
4854 m_originalStream( originalStream ),
4855 m_redirectionStream( redirectionStream ),
4856 m_prevBuf( m_originalStream.rdbuf() ) {}
4857
4858 void startRedirect() {
4859 m_originalStream.rdbuf( m_redirectionStream.rdbuf() );
4860 }
4861 void stopRedirect() { m_originalStream.rdbuf( m_prevBuf ); }
4862 };
4863
4864 /**
4865 * Redirects the `std::cout`, `std::cerr`, `std::clog` streams,
4866 * but does not touch the actual `stdout`/`stderr` file descriptors.
4867 */
4868 class StreamRedirect : public OutputRedirect {
4869 ReusableStringStream m_redirectedOut, m_redirectedErr;
4870 RedirectedStreamNew m_cout, m_cerr, m_clog;
4871
4872 public:
4873 StreamRedirect():
4874 m_cout( Catch::cout(), m_redirectedOut.get() ),
4875 m_cerr( Catch::cerr(), m_redirectedErr.get() ),
4876 m_clog( Catch::clog(), m_redirectedErr.get() ) {}
4877
4878 void activateImpl() override {
4879 m_cout.startRedirect();
4880 m_cerr.startRedirect();
4881 m_clog.startRedirect();
4882 }
4883 void deactivateImpl() override {
4884 m_cout.stopRedirect();
4885 m_cerr.stopRedirect();
4886 m_clog.stopRedirect();
4887 }
4888 std::string getStdout() override { return m_redirectedOut.str(); }
4889 std::string getStderr() override { return m_redirectedErr.str(); }
4890 void clearBuffers() override {
4891 m_redirectedOut.str( "" );
4892 m_redirectedErr.str( "" );
4893 }
4894 };
4895
4896#if defined( CATCH_CONFIG_NEW_CAPTURE )
4897
4898 // Windows's implementation of std::tmpfile is terrible (it tries
4899 // to create a file inside system folder, thus requiring elevated
4900 // privileges for the binary), so we have to use tmpnam(_s) and
4901 // create the file ourselves there.
4902 class TempFile {
4903 public:
4904 TempFile( TempFile const& ) = delete;
4905 TempFile& operator=( TempFile const& ) = delete;
4906 TempFile( TempFile&& ) = delete;
4907 TempFile& operator=( TempFile&& ) = delete;
4908
4909# if defined( _MSC_VER )
4910 TempFile() {
4911 if ( tmpnam_s( m_buffer ) ) {
4912 CATCH_RUNTIME_ERROR( "Could not get a temp filename" );
4913 }
4914 if ( fopen_s( &m_file, m_buffer, "wb+" ) ) {
4915 char buffer[100];
4916 if ( strerror_s( buffer, errno ) ) {
4917 CATCH_RUNTIME_ERROR(
4918 "Could not translate errno to a string" );
4919 }
4920 CATCH_RUNTIME_ERROR( "Could not open the temp file: '"
4921 << m_buffer
4922 << "' because: " << buffer );
4923 }
4924 }
4925# else
4926 TempFile() {
4927 m_file = std::tmpfile();
4928 if ( !m_file ) {
4929 CATCH_RUNTIME_ERROR( "Could not create a temp file." );
4930 }
4931 }
4932# endif
4933
4934 ~TempFile() {
4935 // TBD: What to do about errors here?
4936 std::fclose( m_file );
4937 // We manually create the file on Windows only, on Linux
4938 // it will be autodeleted
4939# if defined( _MSC_VER )
4940 std::remove( m_buffer );
4941# endif
4942 }
4943
4944 std::FILE* getFile() { return m_file; }
4945 std::string getContents() {
4946 ReusableStringStream sstr;
4947 constexpr long buffer_size = 100;
4948 char buffer[buffer_size + 1] = {};
4949 long current_pos = ftell( m_file );
4950 CATCH_ENFORCE( current_pos >= 0,
4951 "ftell failed, errno: " << errno );
4952 std::rewind( m_file );
4953 while ( current_pos > 0 ) {
4954 auto read_characters =
4955 std::fread( buffer,
4956 1,
4957 std::min( buffer_size, current_pos ),
4958 m_file );
4959 buffer[read_characters] = '\0';
4960 sstr << buffer;
4961 current_pos -= static_cast<long>( read_characters );
4962 }
4963 return sstr.str();
4964 }
4965
4966 void clear() { std::rewind( m_file ); }
4967
4968 private:
4969 std::FILE* m_file = nullptr;
4970 char m_buffer[L_tmpnam] = { 0 };
4971 };
4972
4973 /**
4974 * Redirects the actual `stdout`/`stderr` file descriptors.
4975 *
4976 * Works by replacing the file descriptors numbered 1 and 2
4977 * with an open temporary file.
4978 */
4979 class FileRedirect : public OutputRedirect {
4980 TempFile m_outFile, m_errFile;
4981 int m_originalOut = -1;
4982 int m_originalErr = -1;
4983
4984 // Flushes cout/cerr/clog streams and stdout/stderr FDs
4985 void flushEverything() {
4986 Catch::cout() << std::flush;
4987 fflush( stdout );
4988 // Since we support overriding these streams, we flush cerr
4989 // even though std::cerr is unbuffered
4990 Catch::cerr() << std::flush;
4991 Catch::clog() << std::flush;
4992 fflush( stderr );
4993 }
4994
4995 public:
4996 FileRedirect():
4997 m_originalOut( dup( fileno( stdout ) ) ),
4998 m_originalErr( dup( fileno( stderr ) ) ) {
4999 CATCH_ENFORCE( m_originalOut >= 0, "Could not dup stdout" );
5000 CATCH_ENFORCE( m_originalErr >= 0, "Could not dup stderr" );
5001 }
5002
5003 std::string getStdout() override { return m_outFile.getContents(); }
5004 std::string getStderr() override { return m_errFile.getContents(); }
5005 void clearBuffers() override {
5006 m_outFile.clear();
5007 m_errFile.clear();
5008 }
5009
5010 void activateImpl() override {
5011 // We flush before starting redirect, to ensure that we do
5012 // not capture the end of message sent before activation.
5013 flushEverything();
5014
5015 int ret;
5016 ret = dup2( fileno( m_outFile.getFile() ), fileno( stdout ) );
5017 CATCH_ENFORCE( ret >= 0,
5018 "dup2 to stdout has failed, errno: " << errno );
5019 ret = dup2( fileno( m_errFile.getFile() ), fileno( stderr ) );
5020 CATCH_ENFORCE( ret >= 0,
5021 "dup2 to stderr has failed, errno: " << errno );
5022 }
5023 void deactivateImpl() override {
5024 // We flush before ending redirect, to ensure that we
5025 // capture all messages sent while the redirect was active.
5026 flushEverything();
5027
5028 int ret;
5029 ret = dup2( m_originalOut, fileno( stdout ) );
5030 CATCH_ENFORCE(
5031 ret >= 0,
5032 "dup2 of original stdout has failed, errno: " << errno );
5033 ret = dup2( m_originalErr, fileno( stderr ) );
5034 CATCH_ENFORCE(
5035 ret >= 0,
5036 "dup2 of original stderr has failed, errno: " << errno );
5037 }
5038 };
5039
5040#endif // CATCH_CONFIG_NEW_CAPTURE
5041
5042 } // end namespace
5043
5044 bool isRedirectAvailable( OutputRedirect::Kind kind ) {
5045 switch ( kind ) {
5046 // These two are always available
5047 case OutputRedirect::None:
5048 case OutputRedirect::Streams:
5049 return true;
5050#if defined( CATCH_CONFIG_NEW_CAPTURE )
5051 case OutputRedirect::FileDescriptors:
5052 return true;
5053#endif
5054 default:
5055 return false;
5056 }
5057 }
5058
5059 Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual ) {
5060 if ( actual ) {
5061 // TODO: Clean this up later
5062#if defined( CATCH_CONFIG_NEW_CAPTURE )
5063 return Detail::make_unique<FileRedirect>();
5064#else
5065 return Detail::make_unique<StreamRedirect>();
5066#endif
5067 } else {
5068 return Detail::make_unique<NoopRedirect>();
5069 }
5070 }
5071
5072 RedirectGuard scopedActivate( OutputRedirect& redirectImpl ) {
5073 return RedirectGuard( true, redirectImpl );
5074 }
5075
5076 RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl ) {
5077 return RedirectGuard( false, redirectImpl );
5078 }
5079
5080 OutputRedirect::~OutputRedirect() = default;
5081
5082 RedirectGuard::RedirectGuard( bool activate, OutputRedirect& redirectImpl ):
5083 m_redirect( &redirectImpl ),
5084 m_activate( activate ),
5085 m_previouslyActive( redirectImpl.isActive() ) {
5086
5087 // Skip cases where there is no actual state change.
5088 if ( m_activate == m_previouslyActive ) { return; }
5089
5090 if ( m_activate ) {
5091 m_redirect->activate();
5092 } else {
5093 m_redirect->deactivate();
5094 }
5095 }
5096
5097 RedirectGuard::~RedirectGuard() noexcept( false ) {
5098 if ( m_moved ) { return; }
5099 // Skip cases where there is no actual state change.
5100 if ( m_activate == m_previouslyActive ) { return; }
5101
5102 if ( m_activate ) {
5103 m_redirect->deactivate();
5104 } else {
5105 m_redirect->activate();
5106 }
5107 }
5108
5109 RedirectGuard::RedirectGuard( RedirectGuard&& rhs ) noexcept:
5110 m_redirect( rhs.m_redirect ),
5111 m_activate( rhs.m_activate ),
5112 m_previouslyActive( rhs.m_previouslyActive ),
5113 m_moved( false ) {
5114 rhs.m_moved = true;
5115 }
5116
5117 RedirectGuard& RedirectGuard::operator=( RedirectGuard&& rhs ) noexcept {
5118 m_redirect = rhs.m_redirect;
5119 m_activate = rhs.m_activate;
5120 m_previouslyActive = rhs.m_previouslyActive;
5121 m_moved = false;
5122 rhs.m_moved = true;
5123 return *this;
5124 }
5125
5126} // namespace Catch
5127
5128#if defined( CATCH_CONFIG_NEW_CAPTURE )
5129# if defined( _MSC_VER )
5130# undef dup
5131# undef dup2
5132# undef fileno
5133# endif
5134#endif
5135
5136
5137
5138
5139#include <limits>
5140#include <stdexcept>
5141
5142namespace Catch {
5143
5144 Optional<unsigned int> parseUInt(std::string const& input, int base) {
5145 auto trimmed = trim( input );
5146 // std::stoull is annoying and accepts numbers starting with '-',
5147 // it just negates them into unsigned int
5148 if ( trimmed.empty() || trimmed[0] == '-' ) {
5149 return {};
5150 }
5151
5152 CATCH_TRY {
5153 size_t pos = 0;
5154 const auto ret = std::stoull( trimmed, &pos, base );
5155
5156 // We did not consume the whole input, so there is an issue
5157 // This can be bunch of different stuff, like multiple numbers
5158 // in the input, or invalid digits/characters and so on. Either
5159 // way, we do not want to return the partially parsed result.
5160 if ( pos != trimmed.size() ) {
5161 return {};
5162 }
5163 // Too large
5164 if ( ret > std::numeric_limits<unsigned int>::max() ) {
5165 return {};
5166 }
5167 return static_cast<unsigned int>(ret);
5168 }
5169 CATCH_CATCH_ANON( std::invalid_argument const& ) {
5170 // no conversion could be performed
5171 }
5172 CATCH_CATCH_ANON( std::out_of_range const& ) {
5173 // the input does not fit into an unsigned long long
5174 }
5175 return {};
5176 }
5177
5178} // namespace Catch
5179
5180
5181
5182
5183#include <cmath>
5184
5185namespace Catch {
5186
5187#if !defined(CATCH_CONFIG_POLYFILL_ISNAN)
5188 bool isnan(float f) {
5189 return std::isnan(f);
5190 }
5191 bool isnan(double d) {
5192 return std::isnan(d);
5193 }
5194#else
5195 // For now we only use this for embarcadero
5196 bool isnan(float f) {
5197 return std::_isnan(f);
5198 }
5199 bool isnan(double d) {
5200 return std::_isnan(d);
5201 }
5202#endif
5203
5204#if !defined( CATCH_CONFIG_GLOBAL_NEXTAFTER )
5205 float nextafter( float x, float y ) { return std::nextafter( x, y ); }
5206 double nextafter( double x, double y ) { return std::nextafter( x, y ); }
5207#else
5208 float nextafter( float x, float y ) { return ::nextafterf( x, y ); }
5209 double nextafter( double x, double y ) { return ::nextafter( x, y ); }
5210#endif
5211
5212} // end namespace Catch
5213
5214
5215
5216namespace Catch {
5217
5218namespace {
5219
5220#if defined(_MSC_VER)
5221#pragma warning(push)
5222#pragma warning(disable:4146) // we negate uint32 during the rotate
5223#endif
5224 // Safe rotr implementation thanks to John Regehr
5225 uint32_t rotate_right(uint32_t val, uint32_t count) {
5226 const uint32_t mask = 31;
5227 count &= mask;
5228 return (val >> count) | (val << (-count & mask));
5229 }
5230
5231#if defined(_MSC_VER)
5232#pragma warning(pop)
5233#endif
5234
5235}
5236
5237
5238 SimplePcg32::SimplePcg32(result_type seed_) {
5239 seed(seed_);
5240 }
5241
5242
5243 void SimplePcg32::seed(result_type seed_) {
5244 m_state = 0;
5245 (*this)();
5246 m_state += seed_;
5247 (*this)();
5248 }
5249
5250 void SimplePcg32::discard(uint64_t skip) {
5251 // We could implement this to run in O(log n) steps, but this
5252 // should suffice for our use case.
5253 for (uint64_t s = 0; s < skip; ++s) {
5254 static_cast<void>((*this)());
5255 }
5256 }
5257
5258 SimplePcg32::result_type SimplePcg32::operator()() {
5259 // prepare the output value
5260 const uint32_t xorshifted = static_cast<uint32_t>(((m_state >> 18u) ^ m_state) >> 27u);
5261 const auto output = rotate_right(xorshifted, m_state >> 59u);
5262
5263 // advance state
5264 m_state = m_state * 6364136223846793005ULL + s_inc;
5265
5266 return output;
5267 }
5268
5269 bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5270 return lhs.m_state == rhs.m_state;
5271 }
5272
5273 bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs) {
5274 return lhs.m_state != rhs.m_state;
5275 }
5276}
5277
5278
5279
5280
5281
5282#include <ctime>
5283#include <random>
5284
5285namespace Catch {
5286
5287 std::uint32_t generateRandomSeed( GenerateFrom from ) {
5288 switch ( from ) {
5289 case GenerateFrom::Time:
5290 return static_cast<std::uint32_t>( std::time( nullptr ) );
5291
5292 case GenerateFrom::Default:
5293 case GenerateFrom::RandomDevice: {
5294 std::random_device rd;
5295 return Detail::fillBitsFrom<std::uint32_t>( rd );
5296 }
5297
5298 default:
5299 CATCH_ERROR("Unknown generation method");
5300 }
5301 }
5302
5303} // end namespace Catch
5304
5305
5306
5307
5308namespace Catch {
5309 struct ReporterRegistry::ReporterRegistryImpl {
5310 std::vector<Detail::unique_ptr<EventListenerFactory>> listeners;
5311 std::map<std::string, IReporterFactoryPtr, Detail::CaseInsensitiveLess>
5312 factories;
5313 };
5314
5315 ReporterRegistry::ReporterRegistry():
5316 m_impl( Detail::make_unique<ReporterRegistryImpl>() ) {
5317 // Because it is impossible to move out of initializer list,
5318 // we have to add the elements manually
5319 m_impl->factories["Automake"] =
5320 Detail::make_unique<ReporterFactory<AutomakeReporter>>();
5321 m_impl->factories["compact"] =
5322 Detail::make_unique<ReporterFactory<CompactReporter>>();
5323 m_impl->factories["console"] =
5324 Detail::make_unique<ReporterFactory<ConsoleReporter>>();
5325 m_impl->factories["JUnit"] =
5326 Detail::make_unique<ReporterFactory<JunitReporter>>();
5327 m_impl->factories["SonarQube"] =
5328 Detail::make_unique<ReporterFactory<SonarQubeReporter>>();
5329 m_impl->factories["TAP"] =
5330 Detail::make_unique<ReporterFactory<TAPReporter>>();
5331 m_impl->factories["TeamCity"] =
5332 Detail::make_unique<ReporterFactory<TeamCityReporter>>();
5333 m_impl->factories["XML"] =
5334 Detail::make_unique<ReporterFactory<XmlReporter>>();
5335 m_impl->factories["JSON"] =
5336 Detail::make_unique<ReporterFactory<JsonReporter>>();
5337 }
5338
5339 ReporterRegistry::~ReporterRegistry() = default;
5340
5341 IEventListenerPtr
5342 ReporterRegistry::create( std::string const& name,
5343 ReporterConfig&& config ) const {
5344 auto it = m_impl->factories.find( name );
5345 if ( it == m_impl->factories.end() ) return nullptr;
5346 return it->second->create( CATCH_MOVE( config ) );
5347 }
5348
5349 void ReporterRegistry::registerReporter( std::string const& name,
5350 IReporterFactoryPtr factory ) {
5351 CATCH_ENFORCE( name.find( "::" ) == name.npos,
5352 "'::' is not allowed in reporter name: '" + name +
5353 '\'' );
5354 auto ret = m_impl->factories.emplace( name, CATCH_MOVE( factory ) );
5355 CATCH_ENFORCE( ret.second,
5356 "reporter using '" + name +
5357 "' as name was already registered" );
5358 }
5359 void ReporterRegistry::registerListener(
5360 Detail::unique_ptr<EventListenerFactory> factory ) {
5361 m_impl->listeners.push_back( CATCH_MOVE( factory ) );
5362 }
5363
5364 std::map<std::string,
5365 IReporterFactoryPtr,
5366 Detail::CaseInsensitiveLess> const&
5367 ReporterRegistry::getFactories() const {
5368 return m_impl->factories;
5369 }
5370
5371 std::vector<Detail::unique_ptr<EventListenerFactory>> const&
5372 ReporterRegistry::getListeners() const {
5373 return m_impl->listeners;
5374 }
5375} // namespace Catch
5376
5377
5378
5379
5380
5381#include <algorithm>
5382
5383namespace Catch {
5384
5385 namespace {
5386 struct kvPair {
5387 StringRef key, value;
5388 };
5389
5390 kvPair splitKVPair(StringRef kvString) {
5391 auto splitPos = static_cast<size_t>(
5392 std::find( kvString.begin(), kvString.end(), '=' ) -
5393 kvString.begin() );
5394
5395 return { kvString.substr( 0, splitPos ),
5396 kvString.substr( splitPos + 1, kvString.size() ) };
5397 }
5398 }
5399
5400 namespace Detail {
5401 std::vector<std::string> splitReporterSpec( StringRef reporterSpec ) {
5402 static constexpr auto separator = "::";
5403 static constexpr size_t separatorSize = 2;
5404
5405 size_t separatorPos = 0;
5406 auto findNextSeparator = [&reporterSpec]( size_t startPos ) {
5407 static_assert(
5408 separatorSize == 2,
5409 "The code below currently assumes 2 char separator" );
5410
5411 auto currentPos = startPos;
5412 do {
5413 while ( currentPos < reporterSpec.size() &&
5414 reporterSpec[currentPos] != separator[0] ) {
5415 ++currentPos;
5416 }
5417 if ( currentPos + 1 < reporterSpec.size() &&
5418 reporterSpec[currentPos + 1] == separator[1] ) {
5419 return currentPos;
5420 }
5421 ++currentPos;
5422 } while ( currentPos < reporterSpec.size() );
5423
5424 return static_cast<size_t>( -1 );
5425 };
5426
5427 std::vector<std::string> parts;
5428
5429 while ( separatorPos < reporterSpec.size() ) {
5430 const auto nextSeparator = findNextSeparator( separatorPos );
5431 parts.push_back( static_cast<std::string>( reporterSpec.substr(
5432 separatorPos, nextSeparator - separatorPos ) ) );
5433
5434 if ( nextSeparator == static_cast<size_t>( -1 ) ) {
5435 break;
5436 }
5437 separatorPos = nextSeparator + separatorSize;
5438 }
5439
5440 // Handle a separator at the end.
5441 // This is not a valid spec, but we want to do validation in a
5442 // centralized place
5443 if ( separatorPos == reporterSpec.size() ) {
5444 parts.emplace_back();
5445 }
5446
5447 return parts;
5448 }
5449
5450 Optional<ColourMode> stringToColourMode( StringRef colourMode ) {
5451 if ( colourMode == "default" ) {
5452 return ColourMode::PlatformDefault;
5453 } else if ( colourMode == "ansi" ) {
5454 return ColourMode::ANSI;
5455 } else if ( colourMode == "win32" ) {
5456 return ColourMode::Win32;
5457 } else if ( colourMode == "none" ) {
5458 return ColourMode::None;
5459 } else {
5460 return {};
5461 }
5462 }
5463 } // namespace Detail
5464
5465
5466 bool operator==( ReporterSpec const& lhs, ReporterSpec const& rhs ) {
5467 return lhs.m_name == rhs.m_name &&
5468 lhs.m_outputFileName == rhs.m_outputFileName &&
5469 lhs.m_colourMode == rhs.m_colourMode &&
5470 lhs.m_customOptions == rhs.m_customOptions;
5471 }
5472
5473 Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec ) {
5474 auto parts = Detail::splitReporterSpec( reporterSpec );
5475
5476 assert( parts.size() > 0 && "Split should never return empty vector" );
5477
5478 std::map<std::string, std::string> kvPairs;
5479 Optional<std::string> outputFileName;
5480 Optional<ColourMode> colourMode;
5481
5482 // First part is always reporter name, so we skip it
5483 for ( size_t i = 1; i < parts.size(); ++i ) {
5484 auto kv = splitKVPair( parts[i] );
5485 auto key = kv.key, value = kv.value;
5486
5487 if ( key.empty() || value.empty() ) { // NOLINT(bugprone-branch-clone)
5488 return {};
5489 } else if ( key[0] == 'X' ) {
5490 // This is a reporter-specific option, we don't check these
5491 // apart from basic sanity checks
5492 if ( key.size() == 1 ) {
5493 return {};
5494 }
5495
5496 auto ret = kvPairs.emplace( std::string(kv.key), std::string(kv.value) );
5497 if ( !ret.second ) {
5498 // Duplicated key. We might want to handle this differently,
5499 // e.g. by overwriting the existing value?
5500 return {};
5501 }
5502 } else if ( key == "out" ) {
5503 // Duplicated key
5504 if ( outputFileName ) {
5505 return {};
5506 }
5507 outputFileName = static_cast<std::string>( value );
5508 } else if ( key == "colour-mode" ) {
5509 // Duplicated key
5510 if ( colourMode ) {
5511 return {};
5512 }
5513 colourMode = Detail::stringToColourMode( value );
5514 // Parsing failed
5515 if ( !colourMode ) {
5516 return {};
5517 }
5518 } else {
5519 // Unrecognized option
5520 return {};
5521 }
5522 }
5523
5524 return ReporterSpec{ CATCH_MOVE( parts[0] ),
5525 CATCH_MOVE( outputFileName ),
5526 CATCH_MOVE( colourMode ),
5527 CATCH_MOVE( kvPairs ) };
5528 }
5529
5530ReporterSpec::ReporterSpec(
5531 std::string name,
5532 Optional<std::string> outputFileName,
5533 Optional<ColourMode> colourMode,
5534 std::map<std::string, std::string> customOptions ):
5535 m_name( CATCH_MOVE( name ) ),
5536 m_outputFileName( CATCH_MOVE( outputFileName ) ),
5537 m_colourMode( CATCH_MOVE( colourMode ) ),
5538 m_customOptions( CATCH_MOVE( customOptions ) ) {}
5539
5540} // namespace Catch
5541
5542
5543
5544#include <cstdio>
5545#include <sstream>
5546#include <vector>
5547
5548namespace Catch {
5549
5550 // This class encapsulates the idea of a pool of ostringstreams that can be reused.
5551 struct StringStreams {
5552 std::vector<Detail::unique_ptr<std::ostringstream>> m_streams;
5553 std::vector<std::size_t> m_unused;
5554 std::ostringstream m_referenceStream; // Used for copy state/ flags from
5555
5556 auto add() -> std::size_t {
5557 if( m_unused.empty() ) {
5558 m_streams.push_back( Detail::make_unique<std::ostringstream>() );
5559 return m_streams.size()-1;
5560 }
5561 else {
5562 auto index = m_unused.back();
5563 m_unused.pop_back();
5564 return index;
5565 }
5566 }
5567
5568 void release( std::size_t index ) {
5569 m_streams[index]->copyfmt( m_referenceStream ); // Restore initial flags and other state
5570 m_unused.push_back(index);
5571 }
5572 };
5573
5574 ReusableStringStream::ReusableStringStream()
5575 : m_index( Singleton<StringStreams>::getMutable().add() ),
5576 m_oss( Singleton<StringStreams>::getMutable().m_streams[m_index].get() )
5577 {}
5578
5579 ReusableStringStream::~ReusableStringStream() {
5580 static_cast<std::ostringstream*>( m_oss )->str("");
5581 m_oss->clear();
5582 Singleton<StringStreams>::getMutable().release( m_index );
5583 }
5584
5585 std::string ReusableStringStream::str() const {
5586 return static_cast<std::ostringstream*>( m_oss )->str();
5587 }
5588
5589 void ReusableStringStream::str( std::string const& str ) {
5590 static_cast<std::ostringstream*>( m_oss )->str( str );
5591 }
5592
5593
5594}
5595
5596
5597
5598
5599#include <cassert>
5600#include <algorithm>
5601
5602namespace Catch {
5603
5604 namespace Generators {
5605 namespace {
5606 struct GeneratorTracker final : TestCaseTracking::TrackerBase,
5607 IGeneratorTracker {
5608 GeneratorBasePtr m_generator;
5609
5610 GeneratorTracker(
5611 TestCaseTracking::NameAndLocation&& nameAndLocation,
5612 TrackerContext& ctx,
5613 ITracker* parent ):
5614 TrackerBase( CATCH_MOVE( nameAndLocation ), ctx, parent ) {}
5615
5616 static GeneratorTracker*
5617 acquire( TrackerContext& ctx,
5618 TestCaseTracking::NameAndLocationRef const&
5619 nameAndLocation ) {
5620 GeneratorTracker* tracker;
5621
5622 ITracker& currentTracker = ctx.currentTracker();
5623 // Under specific circumstances, the generator we want
5624 // to acquire is also the current tracker. If this is
5625 // the case, we have to avoid looking through current
5626 // tracker's children, and instead return the current
5627 // tracker.
5628 // A case where this check is important is e.g.
5629 // for (int i = 0; i < 5; ++i) {
5630 // int n = GENERATE(1, 2);
5631 // }
5632 //
5633 // without it, the code above creates 5 nested generators.
5634 if ( currentTracker.nameAndLocation() == nameAndLocation ) {
5635 auto thisTracker = currentTracker.parent()->findChild(
5636 nameAndLocation );
5637 assert( thisTracker );
5638 assert( thisTracker->isGeneratorTracker() );
5639 tracker = static_cast<GeneratorTracker*>( thisTracker );
5640 } else if ( ITracker* childTracker =
5641 currentTracker.findChild(
5642 nameAndLocation ) ) {
5643 assert( childTracker );
5644 assert( childTracker->isGeneratorTracker() );
5645 tracker =
5646 static_cast<GeneratorTracker*>( childTracker );
5647 } else {
5648 return nullptr;
5649 }
5650
5651 if ( !tracker->isComplete() ) { tracker->open(); }
5652
5653 return tracker;
5654 }
5655
5656 // TrackerBase interface
5657 bool isGeneratorTracker() const override { return true; }
5658 auto hasGenerator() const -> bool override {
5659 return !!m_generator;
5660 }
5661 void close() override {
5662 TrackerBase::close();
5663 // If a generator has a child (it is followed by a section)
5664 // and none of its children have started, then we must wait
5665 // until later to start consuming its values.
5666 // This catches cases where `GENERATE` is placed between two
5667 // `SECTION`s.
5668 // **The check for m_children.empty cannot be removed**.
5669 // doing so would break `GENERATE` _not_ followed by
5670 // `SECTION`s.
5671 const bool should_wait_for_child = [&]() {
5672 // No children -> nobody to wait for
5673 if ( m_children.empty() ) { return false; }
5674 // If at least one child started executing, don't wait
5675 if ( std::find_if(
5676 m_children.begin(),
5677 m_children.end(),
5678 []( TestCaseTracking::ITrackerPtr const&
5679 tracker ) {
5680 return tracker->hasStarted();
5681 } ) != m_children.end() ) {
5682 return false;
5683 }
5684
5685 // No children have started. We need to check if they
5686 // _can_ start, and thus we should wait for them, or
5687 // they cannot start (due to filters), and we shouldn't
5688 // wait for them
5689 ITracker* parent = m_parent;
5690 // This is safe: there is always at least one section
5691 // tracker in a test case tracking tree
5692 while ( !parent->isSectionTracker() ) {
5693 parent = parent->parent();
5694 }
5695 assert( parent &&
5696 "Missing root (test case) level section" );
5697
5698 auto const& parentSection =
5699 static_cast<SectionTracker const&>( *parent );
5700 auto const& filters = parentSection.getFilters();
5701 // No filters -> no restrictions on running sections
5702 if ( filters.empty() ) { return true; }
5703
5704 for ( auto const& child : m_children ) {
5705 if ( child->isSectionTracker() &&
5706 std::find( filters.begin(),
5707 filters.end(),
5708 static_cast<SectionTracker const&>(
5709 *child )
5710 .trimmedName() ) !=
5711 filters.end() ) {
5712 return true;
5713 }
5714 }
5715 return false;
5716 }();
5717
5718 // This check is a bit tricky, because m_generator->next()
5719 // has a side-effect, where it consumes generator's current
5720 // value, but we do not want to invoke the side-effect if
5721 // this generator is still waiting for any child to start.
5722 assert( m_generator && "Tracker without generator" );
5723 if ( should_wait_for_child ||
5724 ( m_runState == CompletedSuccessfully &&
5725 m_generator->countedNext() ) ) {
5726 m_children.clear();
5727 m_runState = Executing;
5728 }
5729 }
5730
5731 // IGeneratorTracker interface
5732 auto getGenerator() const -> GeneratorBasePtr const& override {
5733 return m_generator;
5734 }
5735 void setGenerator( GeneratorBasePtr&& generator ) override {
5736 m_generator = CATCH_MOVE( generator );
5737 }
5738 };
5739 } // namespace
5740 }
5741
5742 RunContext::RunContext(IConfig const* _config, IEventListenerPtr&& reporter)
5743 : m_runInfo(_config->name()),
5744 m_config(_config),
5745 m_reporter(CATCH_MOVE(reporter)),
5746 m_lastAssertionInfo{ StringRef(), SourceLineInfo("",0), StringRef(), ResultDisposition::Normal },
5747 m_outputRedirect( makeOutputRedirect( m_reporter->getPreferences().shouldRedirectStdOut ) ),
5748 m_includeSuccessfulResults( m_config->includeSuccessfulResults() || m_reporter->getPreferences().shouldReportAllAssertions )
5749 {
5750 getCurrentMutableContext().setResultCapture( this );
5751 m_reporter->testRunStarting(m_runInfo);
5752 }
5753
5754 RunContext::~RunContext() {
5755 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, aborting()));
5756 }
5757
5758 Totals RunContext::runTest(TestCaseHandle const& testCase) {
5759 const Totals prevTotals = m_totals;
5760
5761 auto const& testInfo = testCase.getTestCaseInfo();
5762 m_reporter->testCaseStarting(testInfo);
5763 testCase.prepareTestCase();
5764 m_activeTestCase = &testCase;
5765
5766
5767 ITracker& rootTracker = m_trackerContext.startRun();
5768 assert(rootTracker.isSectionTracker());
5769 static_cast<SectionTracker&>(rootTracker).addInitialFilters(m_config->getSectionsToRun());
5770
5771 // We intentionally only seed the internal RNG once per test case,
5772 // before it is first invoked. The reason for that is a complex
5773 // interplay of generator/section implementation details and the
5774 // Random*Generator types.
5775 //
5776 // The issue boils down to us needing to seed the Random*Generators
5777 // with different seed each, so that they return different sequences
5778 // of random numbers. We do this by giving them a number from the
5779 // shared RNG instance as their seed.
5780 //
5781 // However, this runs into an issue if the reseeding happens each
5782 // time the test case is entered (as opposed to first time only),
5783 // because multiple generators could get the same seed, e.g. in
5784 // ```cpp
5785 // TEST_CASE() {
5786 // auto i = GENERATE(take(10, random(0, 100));
5787 // SECTION("A") {
5788 // auto j = GENERATE(take(10, random(0, 100));
5789 // }
5790 // SECTION("B") {
5791 // auto k = GENERATE(take(10, random(0, 100));
5792 // }
5793 // }
5794 // ```
5795 // `i` and `j` would properly return values from different sequences,
5796 // but `i` and `k` would return the same sequence, because their seed
5797 // would be the same.
5798 // (The reason their seeds would be the same is that the generator
5799 // for k would be initialized when the test case is entered the second
5800 // time, after the shared RNG instance was reset to the same value
5801 // it had when the generator for i was initialized.)
5802 seedRng( *m_config );
5803
5804 uint64_t testRuns = 0;
5805 std::string redirectedCout;
5806 std::string redirectedCerr;
5807 do {
5808 m_trackerContext.startCycle();
5809 m_testCaseTracker = &SectionTracker::acquire(m_trackerContext, TestCaseTracking::NameAndLocationRef(testInfo.name, testInfo.lineInfo));
5810
5811 m_reporter->testCasePartialStarting(testInfo, testRuns);
5812
5813 const auto beforeRunTotals = m_totals;
5814 runCurrentTest();
5815 std::string oneRunCout = m_outputRedirect->getStdout();
5816 std::string oneRunCerr = m_outputRedirect->getStderr();
5817 m_outputRedirect->clearBuffers();
5818 redirectedCout += oneRunCout;
5819 redirectedCerr += oneRunCerr;
5820
5821 const auto singleRunTotals = m_totals.delta(beforeRunTotals);
5822 auto statsForOneRun = TestCaseStats(testInfo, singleRunTotals, CATCH_MOVE(oneRunCout), CATCH_MOVE(oneRunCerr), aborting());
5823 m_reporter->testCasePartialEnded(statsForOneRun, testRuns);
5824
5825 ++testRuns;
5826 } while (!m_testCaseTracker->isSuccessfullyCompleted() && !aborting());
5827
5828 Totals deltaTotals = m_totals.delta(prevTotals);
5829 if (testInfo.expectedToFail() && deltaTotals.testCases.passed > 0) {
5830 deltaTotals.assertions.failed++;
5831 deltaTotals.testCases.passed--;
5832 deltaTotals.testCases.failed++;
5833 }
5834 m_totals.testCases += deltaTotals.testCases;
5835 testCase.tearDownTestCase();
5836 m_reporter->testCaseEnded(TestCaseStats(testInfo,
5837 deltaTotals,
5838 CATCH_MOVE(redirectedCout),
5839 CATCH_MOVE(redirectedCerr),
5840 aborting()));
5841
5842 m_activeTestCase = nullptr;
5843 m_testCaseTracker = nullptr;
5844
5845 return deltaTotals;
5846 }
5847
5848
5849 void RunContext::assertionEnded(AssertionResult&& result) {
5850 if (result.getResultType() == ResultWas::Ok) {
5851 m_totals.assertions.passed++;
5852 m_lastAssertionPassed = true;
5853 } else if (result.getResultType() == ResultWas::ExplicitSkip) {
5854 m_totals.assertions.skipped++;
5855 m_lastAssertionPassed = true;
5856 } else if (!result.succeeded()) {
5857 m_lastAssertionPassed = false;
5858 if (result.isOk()) {
5859 }
5860 else if( m_activeTestCase->getTestCaseInfo().okToFail() )
5861 m_totals.assertions.failedButOk++;
5862 else
5863 m_totals.assertions.failed++;
5864 }
5865 else {
5866 m_lastAssertionPassed = true;
5867 }
5868
5869 {
5870 auto _ = scopedDeactivate( *m_outputRedirect );
5871 m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) );
5872 }
5873
5874 if ( result.getResultType() != ResultWas::Warning ) {
5875 m_messageScopes.clear();
5876 }
5877
5878 // Reset working state. assertion info will be reset after
5879 // populateReaction is run if it is needed
5880 m_lastResult = CATCH_MOVE( result );
5881 }
5882 void RunContext::resetAssertionInfo() {
5883 m_lastAssertionInfo.macroName = StringRef();
5884 m_lastAssertionInfo.capturedExpression = "{Unknown expression after the reported line}"_sr;
5885 m_lastAssertionInfo.resultDisposition = ResultDisposition::Normal;
5886 }
5887
5888 void RunContext::notifyAssertionStarted( AssertionInfo const& info ) {
5889 auto _ = scopedDeactivate( *m_outputRedirect );
5890 m_reporter->assertionStarting( info );
5891 }
5892
5893 bool RunContext::sectionStarted( StringRef sectionName,
5894 SourceLineInfo const& sectionLineInfo,
5895 Counts& assertions ) {
5896 ITracker& sectionTracker =
5897 SectionTracker::acquire( m_trackerContext,
5898 TestCaseTracking::NameAndLocationRef(
5899 sectionName, sectionLineInfo ) );
5900
5901 if (!sectionTracker.isOpen())
5902 return false;
5903 m_activeSections.push_back(&sectionTracker);
5904
5905 SectionInfo sectionInfo( sectionLineInfo, static_cast<std::string>(sectionName) );
5906 m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
5907
5908 {
5909 auto _ = scopedDeactivate( *m_outputRedirect );
5910 m_reporter->sectionStarting( sectionInfo );
5911 }
5912
5913 assertions = m_totals.assertions;
5914
5915 return true;
5916 }
5917 IGeneratorTracker*
5918 RunContext::acquireGeneratorTracker( StringRef generatorName,
5919 SourceLineInfo const& lineInfo ) {
5920 using namespace Generators;
5921 GeneratorTracker* tracker = GeneratorTracker::acquire(
5922 m_trackerContext,
5923 TestCaseTracking::NameAndLocationRef(
5924 generatorName, lineInfo ) );
5925 m_lastAssertionInfo.lineInfo = lineInfo;
5926 return tracker;
5927 }
5928
5929 IGeneratorTracker* RunContext::createGeneratorTracker(
5930 StringRef generatorName,
5931 SourceLineInfo lineInfo,
5932 Generators::GeneratorBasePtr&& generator ) {
5933
5934 auto nameAndLoc = TestCaseTracking::NameAndLocation( static_cast<std::string>( generatorName ), lineInfo );
5935 auto& currentTracker = m_trackerContext.currentTracker();
5936 assert(
5937 currentTracker.nameAndLocation() != nameAndLoc &&
5938 "Trying to create tracker for a genreator that already has one" );
5939
5940 auto newTracker = Catch::Detail::make_unique<Generators::GeneratorTracker>(
5941 CATCH_MOVE(nameAndLoc), m_trackerContext, &currentTracker );
5942 auto ret = newTracker.get();
5943 currentTracker.addChild( CATCH_MOVE( newTracker ) );
5944
5945 ret->setGenerator( CATCH_MOVE( generator ) );
5946 ret->open();
5947 return ret;
5948 }
5949
5950 bool RunContext::testForMissingAssertions(Counts& assertions) {
5951 if (assertions.total() != 0)
5952 return false;
5953 if (!m_config->warnAboutMissingAssertions())
5954 return false;
5955 if (m_trackerContext.currentTracker().hasChildren())
5956 return false;
5957 m_totals.assertions.failed++;
5958 assertions.failed++;
5959 return true;
5960 }
5961
5962 void RunContext::sectionEnded(SectionEndInfo&& endInfo) {
5963 Counts assertions = m_totals.assertions - endInfo.prevAssertions;
5964 bool missingAssertions = testForMissingAssertions(assertions);
5965
5966 if (!m_activeSections.empty()) {
5967 m_activeSections.back()->close();
5968 m_activeSections.pop_back();
5969 }
5970
5971 {
5972 auto _ = scopedDeactivate( *m_outputRedirect );
5973 m_reporter->sectionEnded(
5974 SectionStats( CATCH_MOVE( endInfo.sectionInfo ),
5975 assertions,
5976 endInfo.durationInSeconds,
5977 missingAssertions ) );
5978 }
5979
5980 m_messages.clear();
5981 m_messageScopes.clear();
5982 }
5983
5984 void RunContext::sectionEndedEarly(SectionEndInfo&& endInfo) {
5985 if ( m_unfinishedSections.empty() ) {
5986 m_activeSections.back()->fail();
5987 } else {
5988 m_activeSections.back()->close();
5989 }
5990 m_activeSections.pop_back();
5991
5992 m_unfinishedSections.push_back(CATCH_MOVE(endInfo));
5993 }
5994
5995 void RunContext::benchmarkPreparing( StringRef name ) {
5996 auto _ = scopedDeactivate( *m_outputRedirect );
5997 m_reporter->benchmarkPreparing( name );
5998 }
5999 void RunContext::benchmarkStarting( BenchmarkInfo const& info ) {
6000 auto _ = scopedDeactivate( *m_outputRedirect );
6001 m_reporter->benchmarkStarting( info );
6002 }
6003 void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) {
6004 auto _ = scopedDeactivate( *m_outputRedirect );
6005 m_reporter->benchmarkEnded( stats );
6006 }
6007 void RunContext::benchmarkFailed( StringRef error ) {
6008 auto _ = scopedDeactivate( *m_outputRedirect );
6009 m_reporter->benchmarkFailed( error );
6010 }
6011
6012 void RunContext::pushScopedMessage(MessageInfo const & message) {
6013 m_messages.push_back(message);
6014 }
6015
6016 void RunContext::popScopedMessage(MessageInfo const & message) {
6017 m_messages.erase(std::remove(m_messages.begin(), m_messages.end(), message), m_messages.end());
6018 }
6019
6020 void RunContext::emplaceUnscopedMessage( MessageBuilder&& builder ) {
6021 m_messageScopes.emplace_back( CATCH_MOVE(builder) );
6022 }
6023
6024 std::string RunContext::getCurrentTestName() const {
6025 return m_activeTestCase
6026 ? m_activeTestCase->getTestCaseInfo().name
6027 : std::string();
6028 }
6029
6030 const AssertionResult * RunContext::getLastResult() const {
6031 return &(*m_lastResult);
6032 }
6033
6034 void RunContext::exceptionEarlyReported() {
6035 m_shouldReportUnexpected = false;
6036 }
6037
6038 void RunContext::handleFatalErrorCondition( StringRef message ) {
6039 // TODO: scoped deactivate here? Just give up and do best effort?
6040 // the deactivation can break things further, OTOH so can the
6041 // capture
6042 auto _ = scopedDeactivate( *m_outputRedirect );
6043
6044 // First notify reporter that bad things happened
6045 m_reporter->fatalErrorEncountered( message );
6046
6047 // Don't rebuild the result -- the stringification itself can cause more fatal errors
6048 // Instead, fake a result data.
6049 AssertionResultData tempResult( ResultWas::FatalErrorCondition, { false } );
6050 tempResult.message = static_cast<std::string>(message);
6051 AssertionResult result(m_lastAssertionInfo, CATCH_MOVE(tempResult));
6052
6053 assertionEnded(CATCH_MOVE(result) );
6054 resetAssertionInfo();
6055
6056 // Best effort cleanup for sections that have not been destructed yet
6057 // Since this is a fatal error, we have not had and won't have the opportunity to destruct them properly
6058 while (!m_activeSections.empty()) {
6059 auto nl = m_activeSections.back()->nameAndLocation();
6060 SectionEndInfo endInfo{ SectionInfo(CATCH_MOVE(nl.location), CATCH_MOVE(nl.name)), {}, 0.0 };
6061 sectionEndedEarly(CATCH_MOVE(endInfo));
6062 }
6063 handleUnfinishedSections();
6064
6065 // Recreate section for test case (as we will lose the one that was in scope)
6066 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
6067 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
6068
6069 Counts assertions;
6070 assertions.failed = 1;
6071 SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, 0, false);
6072 m_reporter->sectionEnded( testCaseSectionStats );
6073
6074 auto const& testInfo = m_activeTestCase->getTestCaseInfo();
6075
6076 Totals deltaTotals;
6077 deltaTotals.testCases.failed = 1;
6078 deltaTotals.assertions.failed = 1;
6079 m_reporter->testCaseEnded(TestCaseStats(testInfo,
6080 deltaTotals,
6081 std::string(),
6082 std::string(),
6083 false));
6084 m_totals.testCases.failed++;
6085 m_reporter->testRunEnded(TestRunStats(m_runInfo, m_totals, false));
6086 }
6087
6088 bool RunContext::lastAssertionPassed() {
6089 return m_lastAssertionPassed;
6090 }
6091
6092 void RunContext::assertionPassed() {
6093 m_lastAssertionPassed = true;
6094 ++m_totals.assertions.passed;
6095 resetAssertionInfo();
6096 m_messageScopes.clear();
6097 }
6098
6099 bool RunContext::aborting() const {
6100 return m_totals.assertions.failed >= static_cast<std::size_t>(m_config->abortAfter());
6101 }
6102
6103 void RunContext::runCurrentTest() {
6104 auto const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
6105 SectionInfo testCaseSection(testCaseInfo.lineInfo, testCaseInfo.name);
6106 m_reporter->sectionStarting(testCaseSection);
6107 Counts prevAssertions = m_totals.assertions;
6108 double duration = 0;
6109 m_shouldReportUnexpected = true;
6110 m_lastAssertionInfo = { "TEST_CASE"_sr, testCaseInfo.lineInfo, StringRef(), ResultDisposition::Normal };
6111
6112 Timer timer;
6113 CATCH_TRY {
6114 {
6115 auto _ = scopedActivate( *m_outputRedirect );
6116 timer.start();
6117 invokeActiveTestCase();
6118 }
6119 duration = timer.getElapsedSeconds();
6120 } CATCH_CATCH_ANON (TestFailureException&) {
6121 // This just means the test was aborted due to failure
6122 } CATCH_CATCH_ANON (TestSkipException&) {
6123 // This just means the test was explicitly skipped
6124 } CATCH_CATCH_ALL {
6125 // Under CATCH_CONFIG_FAST_COMPILE, unexpected exceptions under REQUIRE assertions
6126 // are reported without translation at the point of origin.
6127 if( m_shouldReportUnexpected ) {
6128 AssertionReaction dummyReaction;
6129 handleUnexpectedInflightException( m_lastAssertionInfo, translateActiveException(), dummyReaction );
6130 }
6131 }
6132 Counts assertions = m_totals.assertions - prevAssertions;
6133 bool missingAssertions = testForMissingAssertions(assertions);
6134
6135 m_testCaseTracker->close();
6136 handleUnfinishedSections();
6137 m_messages.clear();
6138 m_messageScopes.clear();
6139
6140 SectionStats testCaseSectionStats(CATCH_MOVE(testCaseSection), assertions, duration, missingAssertions);
6141 m_reporter->sectionEnded(testCaseSectionStats);
6142 }
6143
6144 void RunContext::invokeActiveTestCase() {
6145 // We need to engage a handler for signals/structured exceptions
6146 // before running the tests themselves, or the binary can crash
6147 // without failed test being reported.
6148 FatalConditionHandlerGuard _(&m_fatalConditionhandler);
6149 // We keep having issue where some compilers warn about an unused
6150 // variable, even though the type has non-trivial constructor and
6151 // destructor. This is annoying and ugly, but it makes them stfu.
6152 (void)_;
6153
6154 m_activeTestCase->invoke();
6155 }
6156
6157 void RunContext::handleUnfinishedSections() {
6158 // If sections ended prematurely due to an exception we stored their
6159 // infos here so we can tear them down outside the unwind process.
6160 for ( auto it = m_unfinishedSections.rbegin(),
6161 itEnd = m_unfinishedSections.rend();
6162 it != itEnd;
6163 ++it ) {
6164 sectionEnded( CATCH_MOVE( *it ) );
6165 }
6166 m_unfinishedSections.clear();
6167 }
6168
6169 void RunContext::handleExpr(
6170 AssertionInfo const& info,
6171 ITransientExpression const& expr,
6172 AssertionReaction& reaction
6173 ) {
6174 bool negated = isFalseTest( info.resultDisposition );
6175 bool result = expr.getResult() != negated;
6176
6177 if( result ) {
6178 if (!m_includeSuccessfulResults) {
6179 assertionPassed();
6180 }
6181 else {
6182 reportExpr(info, ResultWas::Ok, &expr, negated);
6183 }
6184 }
6185 else {
6186 reportExpr(info, ResultWas::ExpressionFailed, &expr, negated );
6187 populateReaction( reaction );
6188 }
6189 resetAssertionInfo();
6190 }
6191 void RunContext::reportExpr(
6192 AssertionInfo const &info,
6193 ResultWas::OfType resultType,
6194 ITransientExpression const *expr,
6195 bool negated ) {
6196
6197 m_lastAssertionInfo = info;
6198 AssertionResultData data( resultType, LazyExpression( negated ) );
6199
6200 AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6201 assertionResult.m_resultData.lazyExpression.m_transientExpression = expr;
6202
6203 assertionEnded( CATCH_MOVE(assertionResult) );
6204 }
6205
6206 void RunContext::handleMessage(
6207 AssertionInfo const& info,
6208 ResultWas::OfType resultType,
6209 std::string&& message,
6210 AssertionReaction& reaction
6211 ) {
6212 m_lastAssertionInfo = info;
6213
6214 AssertionResultData data( resultType, LazyExpression( false ) );
6215 data.message = CATCH_MOVE( message );
6216 AssertionResult assertionResult{ m_lastAssertionInfo,
6217 CATCH_MOVE( data ) };
6218
6219 const auto isOk = assertionResult.isOk();
6220 assertionEnded( CATCH_MOVE(assertionResult) );
6221 if ( !isOk ) {
6222 populateReaction( reaction );
6223 } else if ( resultType == ResultWas::ExplicitSkip ) {
6224 // TODO: Need to handle this explicitly, as ExplicitSkip is
6225 // considered "OK"
6226 reaction.shouldSkip = true;
6227 }
6228 resetAssertionInfo();
6229 }
6230 void RunContext::handleUnexpectedExceptionNotThrown(
6231 AssertionInfo const& info,
6232 AssertionReaction& reaction
6233 ) {
6234 handleNonExpr(info, Catch::ResultWas::DidntThrowException, reaction);
6235 }
6236
6237 void RunContext::handleUnexpectedInflightException(
6238 AssertionInfo const& info,
6239 std::string&& message,
6240 AssertionReaction& reaction
6241 ) {
6242 m_lastAssertionInfo = info;
6243
6244 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6245 data.message = CATCH_MOVE(message);
6246 AssertionResult assertionResult{ info, CATCH_MOVE(data) };
6247 assertionEnded( CATCH_MOVE(assertionResult) );
6248 populateReaction( reaction );
6249 resetAssertionInfo();
6250 }
6251
6252 void RunContext::populateReaction( AssertionReaction& reaction ) {
6253 reaction.shouldDebugBreak = m_config->shouldDebugBreak();
6254 reaction.shouldThrow = aborting() || (m_lastAssertionInfo.resultDisposition & ResultDisposition::Normal);
6255 }
6256
6257 void RunContext::handleIncomplete(
6258 AssertionInfo const& info
6259 ) {
6260 using namespace std::string_literals;
6261 m_lastAssertionInfo = info;
6262
6263 AssertionResultData data( ResultWas::ThrewException, LazyExpression( false ) );
6264 data.message = "Exception translation was disabled by CATCH_CONFIG_FAST_COMPILE"s;
6265 AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6266 assertionEnded( CATCH_MOVE(assertionResult) );
6267 resetAssertionInfo();
6268 }
6269 void RunContext::handleNonExpr(
6270 AssertionInfo const &info,
6271 ResultWas::OfType resultType,
6272 AssertionReaction &reaction
6273 ) {
6274 m_lastAssertionInfo = info;
6275
6276 AssertionResultData data( resultType, LazyExpression( false ) );
6277 AssertionResult assertionResult{ info, CATCH_MOVE( data ) };
6278
6279 const auto isOk = assertionResult.isOk();
6280 assertionEnded( CATCH_MOVE(assertionResult) );
6281 if ( !isOk ) { populateReaction( reaction ); }
6282 resetAssertionInfo();
6283 }
6284
6285
6286 IResultCapture& getResultCapture() {
6287 if (auto* capture = getCurrentContext().getResultCapture())
6288 return *capture;
6289 else
6290 CATCH_INTERNAL_ERROR("No result capture instance");
6291 }
6292
6293 void seedRng(IConfig const& config) {
6294 sharedRng().seed(config.rngSeed());
6295 }
6296
6297 unsigned int rngSeed() {
6298 return getCurrentContext().getConfig()->rngSeed();
6299 }
6300
6301}
6302
6303
6304
6305namespace Catch {
6306
6307 Section::Section( SectionInfo&& info ):
6308 m_info( CATCH_MOVE( info ) ),
6309 m_sectionIncluded(
6310 getResultCapture().sectionStarted( m_info.name, m_info.lineInfo, m_assertions ) ) {
6311 // Non-"included" sections will not use the timing information
6312 // anyway, so don't bother with the potential syscall.
6313 if (m_sectionIncluded) {
6314 m_timer.start();
6315 }
6316 }
6317
6318 Section::Section( SourceLineInfo const& _lineInfo,
6319 StringRef _name,
6320 const char* const ):
6321 m_info( { "invalid", static_cast<std::size_t>( -1 ) }, std::string{} ),
6322 m_sectionIncluded(
6323 getResultCapture().sectionStarted( _name, _lineInfo, m_assertions ) ) {
6324 // We delay initialization the SectionInfo member until we know
6325 // this section needs it, so we avoid allocating std::string for name.
6326 // We also delay timer start to avoid the potential syscall unless we
6327 // will actually use the result.
6328 if ( m_sectionIncluded ) {
6329 m_info.name = static_cast<std::string>( _name );
6330 m_info.lineInfo = _lineInfo;
6331 m_timer.start();
6332 }
6333 }
6334
6335 Section::~Section() {
6336 if( m_sectionIncluded ) {
6337 SectionEndInfo endInfo{ CATCH_MOVE(m_info), m_assertions, m_timer.getElapsedSeconds() };
6338 if ( uncaught_exceptions() ) {
6339 getResultCapture().sectionEndedEarly( CATCH_MOVE(endInfo) );
6340 } else {
6341 getResultCapture().sectionEnded( CATCH_MOVE( endInfo ) );
6342 }
6343 }
6344 }
6345
6346 // This indicates whether the section should be executed or not
6347 Section::operator bool() const {
6348 return m_sectionIncluded;
6349 }
6350
6351
6352} // end namespace Catch
6353
6354
6355
6356#include <vector>
6357
6358namespace Catch {
6359
6360 namespace {
6361 static auto getSingletons() -> std::vector<ISingleton*>*& {
6362 static std::vector<ISingleton*>* g_singletons = nullptr;
6363 if( !g_singletons )
6364 g_singletons = new std::vector<ISingleton*>();
6365 return g_singletons;
6366 }
6367 }
6368
6369 ISingleton::~ISingleton() = default;
6370
6371 void addSingleton(ISingleton* singleton ) {
6372 getSingletons()->push_back( singleton );
6373 }
6374 void cleanupSingletons() {
6375 auto& singletons = getSingletons();
6376 for( auto singleton : *singletons )
6377 delete singleton;
6378 delete singletons;
6379 singletons = nullptr;
6380 }
6381
6382} // namespace Catch
6383
6384
6385
6386#include <cstring>
6387#include <ostream>
6388
6389namespace Catch {
6390
6391 bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const noexcept {
6392 return line == other.line && (file == other.file || std::strcmp(file, other.file) == 0);
6393 }
6394 bool SourceLineInfo::operator < ( SourceLineInfo const& other ) const noexcept {
6395 // We can assume that the same file will usually have the same pointer.
6396 // Thus, if the pointers are the same, there is no point in calling the strcmp
6397 return line < other.line || ( line == other.line && file != other.file && (std::strcmp(file, other.file) < 0));
6398 }
6399
6400 std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
6401#ifndef __GNUG__
6402 os << info.file << '(' << info.line << ')';
6403#else
6404 os << info.file << ':' << info.line;
6405#endif
6406 return os;
6407 }
6408
6409} // end namespace Catch
6410
6411
6412
6413
6414namespace Catch {
6415#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
6416 void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept {
6417 CATCH_TRY {
6418 m_exceptions.push_back(exception);
6419 } CATCH_CATCH_ALL {
6420 // If we run out of memory during start-up there's really not a lot more we can do about it
6421 std::terminate();
6422 }
6423 }
6424
6425 std::vector<std::exception_ptr> const& StartupExceptionRegistry::getExceptions() const noexcept {
6426 return m_exceptions;
6427 }
6428#endif
6429
6430} // end namespace Catch
6431
6432
6433
6434
6435
6436#include <iostream>
6437
6438namespace Catch {
6439
6440// If you #define this you must implement these functions
6441#if !defined( CATCH_CONFIG_NOSTDOUT )
6442 std::ostream& cout() { return std::cout; }
6443 std::ostream& cerr() { return std::cerr; }
6444 std::ostream& clog() { return std::clog; }
6445#endif
6446
6447} // namespace Catch
6448
6449
6450
6451#include <ostream>
6452#include <cstring>
6453#include <cctype>
6454#include <vector>
6455
6456namespace Catch {
6457
6458 bool startsWith( std::string const& s, std::string const& prefix ) {
6459 return s.size() >= prefix.size() && std::equal(prefix.begin(), prefix.end(), s.begin());
6460 }
6461 bool startsWith( StringRef s, char prefix ) {
6462 return !s.empty() && s[0] == prefix;
6463 }
6464 bool endsWith( std::string const& s, std::string const& suffix ) {
6465 return s.size() >= suffix.size() && std::equal(suffix.rbegin(), suffix.rend(), s.rbegin());
6466 }
6467 bool endsWith( std::string const& s, char suffix ) {
6468 return !s.empty() && s[s.size()-1] == suffix;
6469 }
6470 bool contains( std::string const& s, std::string const& infix ) {
6471 return s.find( infix ) != std::string::npos;
6472 }
6473 void toLowerInPlace( std::string& s ) {
6474 for ( char& c : s ) {
6475 c = toLower( c );
6476 }
6477 }
6478 std::string toLower( std::string const& s ) {
6479 std::string lc = s;
6480 toLowerInPlace( lc );
6481 return lc;
6482 }
6483 char toLower(char c) {
6484 return static_cast<char>(std::tolower(static_cast<unsigned char>(c)));
6485 }
6486
6487 std::string trim( std::string const& str ) {
6488 static char const* whitespaceChars = "\n\r\t ";
6489 std::string::size_type start = str.find_first_not_of( whitespaceChars );
6490 std::string::size_type end = str.find_last_not_of( whitespaceChars );
6491
6492 return start != std::string::npos ? str.substr( start, 1+end-start ) : std::string();
6493 }
6494
6495 StringRef trim(StringRef ref) {
6496 const auto is_ws = [](char c) {
6497 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
6498 };
6499 size_t real_begin = 0;
6500 while (real_begin < ref.size() && is_ws(ref[real_begin])) { ++real_begin; }
6501 size_t real_end = ref.size();
6502 while (real_end > real_begin && is_ws(ref[real_end - 1])) { --real_end; }
6503
6504 return ref.substr(real_begin, real_end - real_begin);
6505 }
6506
6507 bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis ) {
6508 std::size_t i = str.find( replaceThis );
6509 if (i == std::string::npos) {
6510 return false;
6511 }
6512 std::size_t copyBegin = 0;
6513 std::string origStr = CATCH_MOVE(str);
6514 str.clear();
6515 // There is at least one replacement, so reserve with the best guess
6516 // we can make without actually counting the number of occurences.
6517 str.reserve(origStr.size() - replaceThis.size() + withThis.size());
6518 do {
6519 str.append(origStr, copyBegin, i-copyBegin );
6520 str += withThis;
6521 copyBegin = i + replaceThis.size();
6522 if( copyBegin < origStr.size() )
6523 i = origStr.find( replaceThis, copyBegin );
6524 else
6525 i = std::string::npos;
6526 } while( i != std::string::npos );
6527 if ( copyBegin < origStr.size() ) {
6528 str.append(origStr, copyBegin, origStr.size() );
6529 }
6530 return true;
6531 }
6532
6533 std::vector<StringRef> splitStringRef( StringRef str, char delimiter ) {
6534 std::vector<StringRef> subStrings;
6535 std::size_t start = 0;
6536 for(std::size_t pos = 0; pos < str.size(); ++pos ) {
6537 if( str[pos] == delimiter ) {
6538 if( pos - start > 1 )
6539 subStrings.push_back( str.substr( start, pos-start ) );
6540 start = pos+1;
6541 }
6542 }
6543 if( start < str.size() )
6544 subStrings.push_back( str.substr( start, str.size()-start ) );
6545 return subStrings;
6546 }
6547
6548 std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
6549 os << pluraliser.m_count << ' ' << pluraliser.m_label;
6550 if( pluraliser.m_count != 1 )
6551 os << 's';
6552 return os;
6553 }
6554
6555}
6556
6557
6558
6559#include <algorithm>
6560#include <ostream>
6561#include <cstring>
6562#include <cstdint>
6563
6564namespace Catch {
6565 StringRef::StringRef( char const* rawChars ) noexcept
6566 : StringRef( rawChars, std::strlen(rawChars) )
6567 {}
6568
6569
6570 bool StringRef::operator<(StringRef rhs) const noexcept {
6571 if (m_size < rhs.m_size) {
6572 return strncmp(m_start, rhs.m_start, m_size) <= 0;
6573 }
6574 return strncmp(m_start, rhs.m_start, rhs.m_size) < 0;
6575 }
6576
6577 int StringRef::compare( StringRef rhs ) const {
6578 auto cmpResult =
6579 strncmp( m_start, rhs.m_start, std::min( m_size, rhs.m_size ) );
6580
6581 // This means that strncmp found a difference before the strings
6582 // ended, and we can return it directly
6583 if ( cmpResult != 0 ) {
6584 return cmpResult;
6585 }
6586
6587 // If strings are equal up to length, then their comparison results on
6588 // their size
6589 if ( m_size < rhs.m_size ) {
6590 return -1;
6591 } else if ( m_size > rhs.m_size ) {
6592 return 1;
6593 } else {
6594 return 0;
6595 }
6596 }
6597
6598 auto operator << ( std::ostream& os, StringRef str ) -> std::ostream& {
6599 return os.write(str.data(), static_cast<std::streamsize>(str.size()));
6600 }
6601
6602 std::string operator+(StringRef lhs, StringRef rhs) {
6603 std::string ret;
6604 ret.reserve(lhs.size() + rhs.size());
6605 ret += lhs;
6606 ret += rhs;
6607 return ret;
6608 }
6609
6610 auto operator+=( std::string& lhs, StringRef rhs ) -> std::string& {
6611 lhs.append(rhs.data(), rhs.size());
6612 return lhs;
6613 }
6614
6615} // namespace Catch
6616
6617
6618
6619namespace Catch {
6620
6621 TagAliasRegistry::~TagAliasRegistry() = default;
6622
6623 TagAlias const* TagAliasRegistry::find( std::string const& alias ) const {
6624 auto it = m_registry.find( alias );
6625 if( it != m_registry.end() )
6626 return &(it->second);
6627 else
6628 return nullptr;
6629 }
6630
6631 std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
6632 std::string expandedTestSpec = unexpandedTestSpec;
6633 for( auto const& registryKvp : m_registry ) {
6634 std::size_t pos = expandedTestSpec.find( registryKvp.first );
6635 if( pos != std::string::npos ) {
6636 expandedTestSpec = expandedTestSpec.substr( 0, pos ) +
6637 registryKvp.second.tag +
6638 expandedTestSpec.substr( pos + registryKvp.first.size() );
6639 }
6640 }
6641 return expandedTestSpec;
6642 }
6643
6644 void TagAliasRegistry::add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) {
6645 CATCH_ENFORCE( startsWith(alias, "[@") && endsWith(alias, ']'),
6646 "error: tag alias, '" << alias << "' is not of the form [@alias name].\n" << lineInfo );
6647
6648 CATCH_ENFORCE( m_registry.insert(std::make_pair(alias, TagAlias(tag, lineInfo))).second,
6649 "error: tag alias, '" << alias << "' already registered.\n"
6650 << "\tFirst seen at: " << find(alias)->lineInfo << "\n"
6651 << "\tRedefined at: " << lineInfo );
6652 }
6653
6654 ITagAliasRegistry::~ITagAliasRegistry() = default;
6655
6656 ITagAliasRegistry const& ITagAliasRegistry::get() {
6657 return getRegistryHub().getTagAliasRegistry();
6658 }
6659
6660} // end namespace Catch
6661
6662
6663
6664
6665namespace Catch {
6666 TestCaseInfoHasher::TestCaseInfoHasher( hash_t seed ): m_seed( seed ) {}
6667
6668 uint32_t TestCaseInfoHasher::operator()( TestCaseInfo const& t ) const {
6669 // FNV-1a hash algorithm that is designed for uniqueness:
6670 const hash_t prime = 1099511628211u;
6671 hash_t hash = 14695981039346656037u;
6672 for ( const char c : t.name ) {
6673 hash ^= c;
6674 hash *= prime;
6675 }
6676 for ( const char c : t.className ) {
6677 hash ^= c;
6678 hash *= prime;
6679 }
6680 for ( const Tag& tag : t.tags ) {
6681 for ( const char c : tag.original ) {
6682 hash ^= c;
6683 hash *= prime;
6684 }
6685 }
6686 hash ^= m_seed;
6687 hash *= prime;
6688 const uint32_t low{ static_cast<uint32_t>( hash ) };
6689 const uint32_t high{ static_cast<uint32_t>( hash >> 32 ) };
6690 return low * high;
6691 }
6692} // namespace Catch
6693
6694
6695
6696
6697#include <algorithm>
6698#include <set>
6699
6700namespace Catch {
6701
6702 namespace {
6703 static void enforceNoDuplicateTestCases(
6704 std::vector<TestCaseHandle> const& tests ) {
6705 auto testInfoCmp = []( TestCaseInfo const* lhs,
6706 TestCaseInfo const* rhs ) {
6707 return *lhs < *rhs;
6708 };
6709 std::set<TestCaseInfo const*, decltype( testInfoCmp )&> seenTests(
6710 testInfoCmp );
6711 for ( auto const& test : tests ) {
6712 const auto infoPtr = &test.getTestCaseInfo();
6713 const auto prev = seenTests.insert( infoPtr );
6714 CATCH_ENFORCE( prev.second,
6715 "error: test case \""
6716 << infoPtr->name << "\", with tags \""
6717 << infoPtr->tagsAsString()
6718 << "\" already defined.\n"
6719 << "\tFirst seen at "
6720 << ( *prev.first )->lineInfo << "\n"
6721 << "\tRedefined at " << infoPtr->lineInfo );
6722 }
6723 }
6724
6725 static bool matchTest( TestCaseHandle const& testCase,
6726 TestSpec const& testSpec,
6727 IConfig const& config ) {
6728 return testSpec.matches( testCase.getTestCaseInfo() ) &&
6729 isThrowSafe( testCase, config );
6730 }
6731
6732 } // end unnamed namespace
6733
6734 std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases ) {
6735 switch (config.runOrder()) {
6736 case TestRunOrder::Declared:
6737 return unsortedTestCases;
6738
6739 case TestRunOrder::LexicographicallySorted: {
6740 std::vector<TestCaseHandle> sorted = unsortedTestCases;
6741 std::sort(
6742 sorted.begin(),
6743 sorted.end(),
6744 []( TestCaseHandle const& lhs, TestCaseHandle const& rhs ) {
6745 return lhs.getTestCaseInfo() < rhs.getTestCaseInfo();
6746 }
6747 );
6748 return sorted;
6749 }
6750 case TestRunOrder::Randomized: {
6751 using TestWithHash = std::pair<TestCaseInfoHasher::hash_t, TestCaseHandle>;
6752
6753 TestCaseInfoHasher h{ config.rngSeed() };
6754 std::vector<TestWithHash> indexed_tests;
6755 indexed_tests.reserve(unsortedTestCases.size());
6756
6757 for (auto const& handle : unsortedTestCases) {
6758 indexed_tests.emplace_back(h(handle.getTestCaseInfo()), handle);
6759 }
6760
6761 std::sort( indexed_tests.begin(),
6762 indexed_tests.end(),
6763 []( TestWithHash const& lhs, TestWithHash const& rhs ) {
6764 if ( lhs.first == rhs.first ) {
6765 return lhs.second.getTestCaseInfo() <
6766 rhs.second.getTestCaseInfo();
6767 }
6768 return lhs.first < rhs.first;
6769 } );
6770
6771 std::vector<TestCaseHandle> randomized;
6772 randomized.reserve(indexed_tests.size());
6773
6774 for (auto const& indexed : indexed_tests) {
6775 randomized.push_back(indexed.second);
6776 }
6777
6778 return randomized;
6779 }
6780 }
6781
6782 CATCH_INTERNAL_ERROR("Unknown test order value!");
6783 }
6784
6785 bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config ) {
6786 return !testCase.getTestCaseInfo().throws() || config.allowThrows();
6787 }
6788
6789 std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config ) {
6790 std::vector<TestCaseHandle> filtered;
6791 filtered.reserve( testCases.size() );
6792 for (auto const& testCase : testCases) {
6793 if ((!testSpec.hasFilters() && !testCase.getTestCaseInfo().isHidden()) ||
6794 (testSpec.hasFilters() && matchTest(testCase, testSpec, config))) {
6795 filtered.push_back(testCase);
6796 }
6797 }
6798 return createShard(filtered, config.shardCount(), config.shardIndex());
6799 }
6800 std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config ) {
6801 return getRegistryHub().getTestCaseRegistry().getAllTestsSorted( config );
6802 }
6803
6804 TestRegistry::~TestRegistry() = default;
6805
6806 void TestRegistry::registerTest(Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker) {
6807 m_handles.emplace_back(testInfo.get(), testInvoker.get());
6808 m_viewed_test_infos.push_back(testInfo.get());
6809 m_owned_test_infos.push_back(CATCH_MOVE(testInfo));
6810 m_invokers.push_back(CATCH_MOVE(testInvoker));
6811 }
6812
6813 std::vector<TestCaseInfo*> const& TestRegistry::getAllInfos() const {
6814 return m_viewed_test_infos;
6815 }
6816
6817 std::vector<TestCaseHandle> const& TestRegistry::getAllTests() const {
6818 return m_handles;
6819 }
6820 std::vector<TestCaseHandle> const& TestRegistry::getAllTestsSorted( IConfig const& config ) const {
6821 if( m_sortedFunctions.empty() )
6822 enforceNoDuplicateTestCases( m_handles );
6823
6824 if( m_currentSortOrder != config.runOrder() || m_sortedFunctions.empty() ) {
6825 m_sortedFunctions = sortTests( config, m_handles );
6826 m_currentSortOrder = config.runOrder();
6827 }
6828 return m_sortedFunctions;
6829 }
6830
6831} // end namespace Catch
6832
6833
6834
6835
6836#include <algorithm>
6837#include <cassert>
6838
6839#if defined(__clang__)
6840# pragma clang diagnostic push
6841# pragma clang diagnostic ignored "-Wexit-time-destructors"
6842#endif
6843
6844namespace Catch {
6845namespace TestCaseTracking {
6846
6847 NameAndLocation::NameAndLocation( std::string&& _name, SourceLineInfo const& _location )
6848 : name( CATCH_MOVE(_name) ),
6849 location( _location )
6850 {}
6851
6852
6853 ITracker::~ITracker() = default;
6854
6855 void ITracker::markAsNeedingAnotherRun() {
6856 m_runState = NeedsAnotherRun;
6857 }
6858
6859 void ITracker::addChild( ITrackerPtr&& child ) {
6860 m_children.push_back( CATCH_MOVE(child) );
6861 }
6862
6863 ITracker* ITracker::findChild( NameAndLocationRef const& nameAndLocation ) {
6864 auto it = std::find_if(
6865 m_children.begin(),
6866 m_children.end(),
6867 [&nameAndLocation]( ITrackerPtr const& tracker ) {
6868 auto const& tnameAndLoc = tracker->nameAndLocation();
6869 if ( tnameAndLoc.location.line !=
6870 nameAndLocation.location.line ) {
6871 return false;
6872 }
6873 return tnameAndLoc == nameAndLocation;
6874 } );
6875 return ( it != m_children.end() ) ? it->get() : nullptr;
6876 }
6877
6878 bool ITracker::isSectionTracker() const { return false; }
6879 bool ITracker::isGeneratorTracker() const { return false; }
6880
6881 bool ITracker::isOpen() const {
6882 return m_runState != NotStarted && !isComplete();
6883 }
6884
6885 bool ITracker::hasStarted() const { return m_runState != NotStarted; }
6886
6887 void ITracker::openChild() {
6888 if (m_runState != ExecutingChildren) {
6889 m_runState = ExecutingChildren;
6890 if (m_parent) {
6891 m_parent->openChild();
6892 }
6893 }
6894 }
6895
6896 ITracker& TrackerContext::startRun() {
6897 using namespace std::string_literals;
6898 m_rootTracker = Catch::Detail::make_unique<SectionTracker>(
6899 NameAndLocation( "{root}"s, CATCH_INTERNAL_LINEINFO ),
6900 *this,
6901 nullptr );
6902 m_currentTracker = nullptr;
6903 m_runState = Executing;
6904 return *m_rootTracker;
6905 }
6906
6907 void TrackerContext::completeCycle() {
6908 m_runState = CompletedCycle;
6909 }
6910
6911 bool TrackerContext::completedCycle() const {
6912 return m_runState == CompletedCycle;
6913 }
6914 void TrackerContext::setCurrentTracker( ITracker* tracker ) {
6915 m_currentTracker = tracker;
6916 }
6917
6918
6919 TrackerBase::TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent ):
6920 ITracker(CATCH_MOVE(nameAndLocation), parent),
6921 m_ctx( ctx )
6922 {}
6923
6924 bool TrackerBase::isComplete() const {
6925 return m_runState == CompletedSuccessfully || m_runState == Failed;
6926 }
6927
6928 void TrackerBase::open() {
6929 m_runState = Executing;
6930 moveToThis();
6931 if( m_parent )
6932 m_parent->openChild();
6933 }
6934
6935 void TrackerBase::close() {
6936
6937 // Close any still open children (e.g. generators)
6938 while( &m_ctx.currentTracker() != this )
6939 m_ctx.currentTracker().close();
6940
6941 switch( m_runState ) {
6942 case NeedsAnotherRun:
6943 break;
6944
6945 case Executing:
6946 m_runState = CompletedSuccessfully;
6947 break;
6948 case ExecutingChildren:
6949 if( std::all_of(m_children.begin(), m_children.end(), [](ITrackerPtr const& t){ return t->isComplete(); }) )
6950 m_runState = CompletedSuccessfully;
6951 break;
6952
6953 case NotStarted:
6954 case CompletedSuccessfully:
6955 case Failed:
6956 CATCH_INTERNAL_ERROR( "Illogical state: " << m_runState );
6957
6958 default:
6959 CATCH_INTERNAL_ERROR( "Unknown state: " << m_runState );
6960 }
6961 moveToParent();
6962 m_ctx.completeCycle();
6963 }
6964 void TrackerBase::fail() {
6965 m_runState = Failed;
6966 if( m_parent )
6967 m_parent->markAsNeedingAnotherRun();
6968 moveToParent();
6969 m_ctx.completeCycle();
6970 }
6971
6972 void TrackerBase::moveToParent() {
6973 assert( m_parent );
6974 m_ctx.setCurrentTracker( m_parent );
6975 }
6976 void TrackerBase::moveToThis() {
6977 m_ctx.setCurrentTracker( this );
6978 }
6979
6980 SectionTracker::SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent )
6981 : TrackerBase( CATCH_MOVE(nameAndLocation), ctx, parent ),
6982 m_trimmed_name(trim(StringRef(ITracker::nameAndLocation().name)))
6983 {
6984 if( parent ) {
6985 while ( !parent->isSectionTracker() ) {
6986 parent = parent->parent();
6987 }
6988
6989 SectionTracker& parentSection = static_cast<SectionTracker&>( *parent );
6990 addNextFilters( parentSection.m_filters );
6991 }
6992 }
6993
6994 bool SectionTracker::isComplete() const {
6995 bool complete = true;
6996
6997 if (m_filters.empty()
6998 || m_filters[0].empty()
6999 || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) {
7000 complete = TrackerBase::isComplete();
7001 }
7002 return complete;
7003 }
7004
7005 bool SectionTracker::isSectionTracker() const { return true; }
7006
7007 SectionTracker& SectionTracker::acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation ) {
7008 SectionTracker* tracker;
7009
7010 ITracker& currentTracker = ctx.currentTracker();
7011 if ( ITracker* childTracker =
7012 currentTracker.findChild( nameAndLocation ) ) {
7013 assert( childTracker );
7014 assert( childTracker->isSectionTracker() );
7015 tracker = static_cast<SectionTracker*>( childTracker );
7016 } else {
7017 auto newTracker = Catch::Detail::make_unique<SectionTracker>(
7018 NameAndLocation{ static_cast<std::string>(nameAndLocation.name),
7019 nameAndLocation.location },
7020 ctx,
7021 &currentTracker );
7022 tracker = newTracker.get();
7023 currentTracker.addChild( CATCH_MOVE( newTracker ) );
7024 }
7025
7026 if ( !ctx.completedCycle() ) {
7027 tracker->tryOpen();
7028 }
7029
7030 return *tracker;
7031 }
7032
7033 void SectionTracker::tryOpen() {
7034 if( !isComplete() )
7035 open();
7036 }
7037
7038 void SectionTracker::addInitialFilters( std::vector<std::string> const& filters ) {
7039 if( !filters.empty() ) {
7040 m_filters.reserve( m_filters.size() + filters.size() + 2 );
7041 m_filters.emplace_back(StringRef{}); // Root - should never be consulted
7042 m_filters.emplace_back(StringRef{}); // Test Case - not a section filter
7043 m_filters.insert( m_filters.end(), filters.begin(), filters.end() );
7044 }
7045 }
7046 void SectionTracker::addNextFilters( std::vector<StringRef> const& filters ) {
7047 if( filters.size() > 1 )
7048 m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() );
7049 }
7050
7051 StringRef SectionTracker::trimmedName() const {
7052 return m_trimmed_name;
7053 }
7054
7055} // namespace TestCaseTracking
7056
7057} // namespace Catch
7058
7059#if defined(__clang__)
7060# pragma clang diagnostic pop
7061#endif
7062
7063
7064
7065
7066namespace Catch {
7067
7068 void throw_test_failure_exception() {
7069#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
7070 throw TestFailureException{};
7071#else
7072 CATCH_ERROR( "Test failure requires aborting test!" );
7073#endif
7074 }
7075
7076 void throw_test_skip_exception() {
7077#if !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS )
7078 throw Catch::TestSkipException();
7079#else
7080 CATCH_ERROR( "Explicitly skipping tests during runtime requires exceptions" );
7081#endif
7082 }
7083
7084} // namespace Catch
7085
7086
7087
7088#include <algorithm>
7089#include <iterator>
7090
7091namespace Catch {
7092 void ITestInvoker::prepareTestCase() {}
7093 void ITestInvoker::tearDownTestCase() {}
7094 ITestInvoker::~ITestInvoker() = default;
7095
7096 namespace {
7097 static StringRef extractClassName( StringRef classOrMethodName ) {
7098 if ( !startsWith( classOrMethodName, '&' ) ) {
7099 return classOrMethodName;
7100 }
7101
7102 // Remove the leading '&' to avoid having to special case it later
7103 const auto methodName =
7104 classOrMethodName.substr( 1, classOrMethodName.size() );
7105
7106 auto reverseStart = std::make_reverse_iterator( methodName.end() );
7107 auto reverseEnd = std::make_reverse_iterator( methodName.begin() );
7108
7109 // We make a simplifying assumption that ":" is only present
7110 // in the input as part of "::" from C++ typenames (this is
7111 // relatively safe assumption because the input is generated
7112 // as stringification of type through preprocessor).
7113 auto lastColons = std::find( reverseStart, reverseEnd, ':' ) + 1;
7114 auto secondLastColons =
7115 std::find( lastColons + 1, reverseEnd, ':' );
7116
7117 auto const startIdx = reverseEnd - secondLastColons;
7118 auto const classNameSize = secondLastColons - lastColons - 1;
7119
7120 return methodName.substr(
7121 static_cast<std::size_t>( startIdx ),
7122 static_cast<std::size_t>( classNameSize ) );
7123 }
7124
7125 class TestInvokerAsFunction final : public ITestInvoker {
7126 using TestType = void ( * )();
7127 TestType m_testAsFunction;
7128
7129 public:
7130 constexpr TestInvokerAsFunction( TestType testAsFunction ) noexcept:
7131 m_testAsFunction( testAsFunction ) {}
7132
7133 void invoke() const override { m_testAsFunction(); }
7134 };
7135
7136 } // namespace
7137
7138 Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() ) {
7139 return Detail::make_unique<TestInvokerAsFunction>( testAsFunction );
7140 }
7141
7142 AutoReg::AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept {
7143 CATCH_TRY {
7144 getMutableRegistryHub()
7145 .registerTest(
7146 makeTestCaseInfo(
7147 extractClassName( classOrMethod ),
7148 nameAndTags,
7149 lineInfo),
7150 CATCH_MOVE(invoker)
7151 );
7152 } CATCH_CATCH_ALL {
7153 // Do not throw when constructing global objects, instead register the exception to be processed later
7154 getMutableRegistryHub().registerStartupException();
7155 }
7156 }
7157}
7158
7159
7160
7161
7162
7163namespace Catch {
7164
7165 TestSpecParser::TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
7166
7167 TestSpecParser& TestSpecParser::parse( std::string const& arg ) {
7168 m_mode = None;
7169 m_exclusion = false;
7170 m_arg = m_tagAliases->expandAliases( arg );
7171 m_escapeChars.clear();
7172 m_substring.reserve(m_arg.size());
7173 m_patternName.reserve(m_arg.size());
7174 m_realPatternPos = 0;
7175
7176 for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
7177 //if visitChar fails
7178 if( !visitChar( m_arg[m_pos] ) ){
7179 m_testSpec.m_invalidSpecs.push_back(arg);
7180 break;
7181 }
7182 endMode();
7183 return *this;
7184 }
7185 TestSpec TestSpecParser::testSpec() {
7186 addFilter();
7187 return CATCH_MOVE(m_testSpec);
7188 }
7189 bool TestSpecParser::visitChar( char c ) {
7190 if( (m_mode != EscapedName) && (c == '\\') ) {
7191 escape();
7192 addCharToPattern(c);
7193 return true;
7194 }else if((m_mode != EscapedName) && (c == ',') ) {
7195 return separate();
7196 }
7197
7198 switch( m_mode ) {
7199 case None:
7200 if( processNoneChar( c ) )
7201 return true;
7202 break;
7203 case Name:
7204 processNameChar( c );
7205 break;
7206 case EscapedName:
7207 endMode();
7208 addCharToPattern(c);
7209 return true;
7210 default:
7211 case Tag:
7212 case QuotedName:
7213 if( processOtherChar( c ) )
7214 return true;
7215 break;
7216 }
7217
7218 m_substring += c;
7219 if( !isControlChar( c ) ) {
7220 m_patternName += c;
7221 m_realPatternPos++;
7222 }
7223 return true;
7224 }
7225 // Two of the processing methods return true to signal the caller to return
7226 // without adding the given character to the current pattern strings
7227 bool TestSpecParser::processNoneChar( char c ) {
7228 switch( c ) {
7229 case ' ':
7230 return true;
7231 case '~':
7232 m_exclusion = true;
7233 return false;
7234 case '[':
7235 startNewMode( Tag );
7236 return false;
7237 case '"':
7238 startNewMode( QuotedName );
7239 return false;
7240 default:
7241 startNewMode( Name );
7242 return false;
7243 }
7244 }
7245 void TestSpecParser::processNameChar( char c ) {
7246 if( c == '[' ) {
7247 if( m_substring == "exclude:" )
7248 m_exclusion = true;
7249 else
7250 endMode();
7251 startNewMode( Tag );
7252 }
7253 }
7254 bool TestSpecParser::processOtherChar( char c ) {
7255 if( !isControlChar( c ) )
7256 return false;
7257 m_substring += c;
7258 endMode();
7259 return true;
7260 }
7261 void TestSpecParser::startNewMode( Mode mode ) {
7262 m_mode = mode;
7263 }
7264 void TestSpecParser::endMode() {
7265 switch( m_mode ) {
7266 case Name:
7267 case QuotedName:
7268 return addNamePattern();
7269 case Tag:
7270 return addTagPattern();
7271 case EscapedName:
7272 revertBackToLastMode();
7273 return;
7274 case None:
7275 default:
7276 return startNewMode( None );
7277 }
7278 }
7279 void TestSpecParser::escape() {
7280 saveLastMode();
7281 m_mode = EscapedName;
7282 m_escapeChars.push_back(m_realPatternPos);
7283 }
7284 bool TestSpecParser::isControlChar( char c ) const {
7285 switch( m_mode ) {
7286 default:
7287 return false;
7288 case None:
7289 return c == '~';
7290 case Name:
7291 return c == '[';
7292 case EscapedName:
7293 return true;
7294 case QuotedName:
7295 return c == '"';
7296 case Tag:
7297 return c == '[' || c == ']';
7298 }
7299 }
7300
7301 void TestSpecParser::addFilter() {
7302 if( !m_currentFilter.m_required.empty() || !m_currentFilter.m_forbidden.empty() ) {
7303 m_testSpec.m_filters.push_back( CATCH_MOVE(m_currentFilter) );
7304 m_currentFilter = TestSpec::Filter();
7305 }
7306 }
7307
7308 void TestSpecParser::saveLastMode() {
7309 lastMode = m_mode;
7310 }
7311
7312 void TestSpecParser::revertBackToLastMode() {
7313 m_mode = lastMode;
7314 }
7315
7316 bool TestSpecParser::separate() {
7317 if( (m_mode==QuotedName) || (m_mode==Tag) ){
7318 //invalid argument, signal failure to previous scope.
7319 m_mode = None;
7320 m_pos = m_arg.size();
7321 m_substring.clear();
7322 m_patternName.clear();
7323 m_realPatternPos = 0;
7324 return false;
7325 }
7326 endMode();
7327 addFilter();
7328 return true; //success
7329 }
7330
7331 std::string TestSpecParser::preprocessPattern() {
7332 std::string token = m_patternName;
7333 for (std::size_t i = 0; i < m_escapeChars.size(); ++i)
7334 token = token.substr(0, m_escapeChars[i] - i) + token.substr(m_escapeChars[i] - i + 1);
7335 m_escapeChars.clear();
7336 if (startsWith(token, "exclude:")) {
7337 m_exclusion = true;
7338 token = token.substr(8);
7339 }
7340
7341 m_patternName.clear();
7342 m_realPatternPos = 0;
7343
7344 return token;
7345 }
7346
7347 void TestSpecParser::addNamePattern() {
7348 auto token = preprocessPattern();
7349
7350 if (!token.empty()) {
7351 if (m_exclusion) {
7352 m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7353 } else {
7354 m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::NamePattern>(token, m_substring));
7355 }
7356 }
7357 m_substring.clear();
7358 m_exclusion = false;
7359 m_mode = None;
7360 }
7361
7362 void TestSpecParser::addTagPattern() {
7363 auto token = preprocessPattern();
7364
7365 if (!token.empty()) {
7366 // If the tag pattern is the "hide and tag" shorthand (e.g. [.foo])
7367 // we have to create a separate hide tag and shorten the real one
7368 if (token.size() > 1 && token[0] == '.') {
7369 token.erase(token.begin());
7370 if (m_exclusion) {
7371 m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7372 } else {
7373 m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(".", m_substring));
7374 }
7375 }
7376 if (m_exclusion) {
7377 m_currentFilter.m_forbidden.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7378 } else {
7379 m_currentFilter.m_required.emplace_back(Detail::make_unique<TestSpec::TagPattern>(token, m_substring));
7380 }
7381 }
7382 m_substring.clear();
7383 m_exclusion = false;
7384 m_mode = None;
7385 }
7386
7387} // namespace Catch
7388
7389
7390
7391#include <algorithm>
7392#include <cstring>
7393#include <ostream>
7394
7395namespace {
7396 bool isWhitespace( char c ) {
7397 return c == ' ' || c == '\t' || c == '\n' || c == '\r';
7398 }
7399
7400 bool isBreakableBefore( char c ) {
7401 static const char chars[] = "[({<|";
7402 return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7403 }
7404
7405 bool isBreakableAfter( char c ) {
7406 static const char chars[] = "])}>.,:;*+-=&/\\";
7407 return std::memchr( chars, c, sizeof( chars ) - 1 ) != nullptr;
7408 }
7409
7410} // namespace
7411
7412namespace Catch {
7413 namespace TextFlow {
7414 void AnsiSkippingString::preprocessString() {
7415 for ( auto it = m_string.begin(); it != m_string.end(); ) {
7416 // try to read through an ansi sequence
7417 while ( it != m_string.end() && *it == '\033' &&
7418 it + 1 != m_string.end() && *( it + 1 ) == '[' ) {
7419 auto cursor = it + 2;
7420 while ( cursor != m_string.end() &&
7421 ( isdigit( *cursor ) || *cursor == ';' ) ) {
7422 ++cursor;
7423 }
7424 if ( cursor == m_string.end() || *cursor != 'm' ) {
7425 break;
7426 }
7427 // 'm' -> 0xff
7428 *cursor = AnsiSkippingString::sentinel;
7429 // if we've read an ansi sequence, set the iterator and
7430 // return to the top of the loop
7431 it = cursor + 1;
7432 }
7433 if ( it != m_string.end() ) {
7434 ++m_size;
7435 ++it;
7436 }
7437 }
7438 }
7439
7440 AnsiSkippingString::AnsiSkippingString( std::string const& text ):
7441 m_string( text ) {
7442 preprocessString();
7443 }
7444
7445 AnsiSkippingString::AnsiSkippingString( std::string&& text ):
7446 m_string( CATCH_MOVE( text ) ) {
7447 preprocessString();
7448 }
7449
7450 AnsiSkippingString::const_iterator AnsiSkippingString::begin() const {
7451 return const_iterator( m_string );
7452 }
7453
7454 AnsiSkippingString::const_iterator AnsiSkippingString::end() const {
7455 return const_iterator( m_string, const_iterator::EndTag{} );
7456 }
7457
7458 std::string AnsiSkippingString::substring( const_iterator begin,
7459 const_iterator end ) const {
7460 // There's one caveat here to an otherwise simple substring: when
7461 // making a begin iterator we might have skipped ansi sequences at
7462 // the start. If `begin` here is a begin iterator, skipped over
7463 // initial ansi sequences, we'll use the true beginning of the
7464 // string. Lastly: We need to transform any chars we replaced with
7465 // 0xff back to 'm'
7466 auto str = std::string( begin == this->begin() ? m_string.begin()
7467 : begin.m_it,
7468 end.m_it );
7469 std::transform( str.begin(), str.end(), str.begin(), []( char c ) {
7470 return c == AnsiSkippingString::sentinel ? 'm' : c;
7471 } );
7472 return str;
7473 }
7474
7475 void AnsiSkippingString::const_iterator::tryParseAnsiEscapes() {
7476 // check if we've landed on an ansi sequence, and if so read through
7477 // it
7478 while ( m_it != m_string->end() && *m_it == '\033' &&
7479 m_it + 1 != m_string->end() && *( m_it + 1 ) == '[' ) {
7480 auto cursor = m_it + 2;
7481 while ( cursor != m_string->end() &&
7482 ( isdigit( *cursor ) || *cursor == ';' ) ) {
7483 ++cursor;
7484 }
7485 if ( cursor == m_string->end() ||
7486 *cursor != AnsiSkippingString::sentinel ) {
7487 break;
7488 }
7489 // if we've read an ansi sequence, set the iterator and
7490 // return to the top of the loop
7491 m_it = cursor + 1;
7492 }
7493 }
7494
7495 void AnsiSkippingString::const_iterator::advance() {
7496 assert( m_it != m_string->end() );
7497 m_it++;
7498 tryParseAnsiEscapes();
7499 }
7500
7501 void AnsiSkippingString::const_iterator::unadvance() {
7502 assert( m_it != m_string->begin() );
7503 m_it--;
7504 // if *m_it is 0xff, scan back to the \033 and then m_it-- once more
7505 // (and repeat check)
7506 while ( *m_it == AnsiSkippingString::sentinel ) {
7507 while ( *m_it != '\033' ) {
7508 assert( m_it != m_string->begin() );
7509 m_it--;
7510 }
7511 // if this happens, we must have been a begin iterator that had
7512 // skipped over ansi sequences at the start of a string
7513 assert( m_it != m_string->begin() );
7514 assert( *m_it == '\033' );
7515 m_it--;
7516 }
7517 }
7518
7519 static bool isBoundary( AnsiSkippingString const& line,
7520 AnsiSkippingString::const_iterator it ) {
7521 return it == line.end() ||
7522 ( isWhitespace( *it ) &&
7523 !isWhitespace( *it.oneBefore() ) ) ||
7524 isBreakableBefore( *it ) ||
7525 isBreakableAfter( *it.oneBefore() );
7526 }
7527
7528 void Column::const_iterator::calcLength() {
7529 m_addHyphen = false;
7530 m_parsedTo = m_lineStart;
7531 AnsiSkippingString const& current_line = m_column.m_string;
7532
7533 if ( m_parsedTo == current_line.end() ) {
7534 m_lineEnd = m_parsedTo;
7535 return;
7536 }
7537
7538 assert( m_lineStart != current_line.end() );
7539 if ( *m_lineStart == '\n' ) { ++m_parsedTo; }
7540
7541 const auto maxLineLength = m_column.m_width - indentSize();
7542 std::size_t lineLength = 0;
7543 while ( m_parsedTo != current_line.end() &&
7544 lineLength < maxLineLength && *m_parsedTo != '\n' ) {
7545 ++m_parsedTo;
7546 ++lineLength;
7547 }
7548
7549 // If we encountered a newline before the column is filled,
7550 // then we linebreak at the newline and consider this line
7551 // finished.
7552 if ( lineLength < maxLineLength ) {
7553 m_lineEnd = m_parsedTo;
7554 } else {
7555 // Look for a natural linebreak boundary in the column
7556 // (We look from the end, so that the first found boundary is
7557 // the right one)
7558 m_lineEnd = m_parsedTo;
7559 while ( lineLength > 0 &&
7560 !isBoundary( current_line, m_lineEnd ) ) {
7561 --lineLength;
7562 --m_lineEnd;
7563 }
7564 while ( lineLength > 0 &&
7565 isWhitespace( *m_lineEnd.oneBefore() ) ) {
7566 --lineLength;
7567 --m_lineEnd;
7568 }
7569
7570 // If we found one, then that is where we linebreak, otherwise
7571 // we have to split text with a hyphen
7572 if ( lineLength == 0 ) {
7573 m_addHyphen = true;
7574 m_lineEnd = m_parsedTo.oneBefore();
7575 }
7576 }
7577 }
7578
7579 size_t Column::const_iterator::indentSize() const {
7580 auto initial = m_lineStart == m_column.m_string.begin()
7581 ? m_column.m_initialIndent
7582 : std::string::npos;
7583 return initial == std::string::npos ? m_column.m_indent : initial;
7584 }
7585
7586 std::string Column::const_iterator::addIndentAndSuffix(
7587 AnsiSkippingString::const_iterator start,
7588 AnsiSkippingString::const_iterator end ) const {
7589 std::string ret;
7590 const auto desired_indent = indentSize();
7591 // ret.reserve( desired_indent + (end - start) + m_addHyphen );
7592 ret.append( desired_indent, ' ' );
7593 // ret.append( start, end );
7594 ret += m_column.m_string.substring( start, end );
7595 if ( m_addHyphen ) { ret.push_back( '-' ); }
7596
7597 return ret;
7598 }
7599
7600 Column::const_iterator::const_iterator( Column const& column ):
7601 m_column( column ),
7602 m_lineStart( column.m_string.begin() ),
7603 m_lineEnd( column.m_string.begin() ),
7604 m_parsedTo( column.m_string.begin() ) {
7605 assert( m_column.m_width > m_column.m_indent );
7606 assert( m_column.m_initialIndent == std::string::npos ||
7607 m_column.m_width > m_column.m_initialIndent );
7608 calcLength();
7609 if ( m_lineStart == m_lineEnd ) {
7610 m_lineStart = m_column.m_string.end();
7611 }
7612 }
7613
7614 std::string Column::const_iterator::operator*() const {
7615 assert( m_lineStart <= m_parsedTo );
7616 return addIndentAndSuffix( m_lineStart, m_lineEnd );
7617 }
7618
7619 Column::const_iterator& Column::const_iterator::operator++() {
7620 m_lineStart = m_lineEnd;
7621 AnsiSkippingString const& current_line = m_column.m_string;
7622 if ( m_lineStart != current_line.end() && *m_lineStart == '\n' ) {
7623 m_lineStart++;
7624 } else {
7625 while ( m_lineStart != current_line.end() &&
7626 isWhitespace( *m_lineStart ) ) {
7627 ++m_lineStart;
7628 }
7629 }
7630
7631 if ( m_lineStart != current_line.end() ) { calcLength(); }
7632 return *this;
7633 }
7634
7635 Column::const_iterator Column::const_iterator::operator++( int ) {
7636 const_iterator prev( *this );
7637 operator++();
7638 return prev;
7639 }
7640
7641 std::ostream& operator<<( std::ostream& os, Column const& col ) {
7642 bool first = true;
7643 for ( auto line : col ) {
7644 if ( first ) {
7645 first = false;
7646 } else {
7647 os << '\n';
7648 }
7649 os << line;
7650 }
7651 return os;
7652 }
7653
7654 Column Spacer( size_t spaceWidth ) {
7655 Column ret{ "" };
7656 ret.width( spaceWidth );
7657 return ret;
7658 }
7659
7660 Columns::iterator::iterator( Columns const& columns, EndTag ):
7661 m_columns( columns.m_columns ), m_activeIterators( 0 ) {
7662
7663 m_iterators.reserve( m_columns.size() );
7664 for ( auto const& col : m_columns ) {
7665 m_iterators.push_back( col.end() );
7666 }
7667 }
7668
7669 Columns::iterator::iterator( Columns const& columns ):
7670 m_columns( columns.m_columns ),
7671 m_activeIterators( m_columns.size() ) {
7672
7673 m_iterators.reserve( m_columns.size() );
7674 for ( auto const& col : m_columns ) {
7675 m_iterators.push_back( col.begin() );
7676 }
7677 }
7678
7679 std::string Columns::iterator::operator*() const {
7680 std::string row, padding;
7681
7682 for ( size_t i = 0; i < m_columns.size(); ++i ) {
7683 const auto width = m_columns[i].width();
7684 if ( m_iterators[i] != m_columns[i].end() ) {
7685 std::string col = *m_iterators[i];
7686 row += padding;
7687 row += col;
7688
7689 padding.clear();
7690 if ( col.size() < width ) {
7691 padding.append( width - col.size(), ' ' );
7692 }
7693 } else {
7694 padding.append( width, ' ' );
7695 }
7696 }
7697 return row;
7698 }
7699
7700 Columns::iterator& Columns::iterator::operator++() {
7701 for ( size_t i = 0; i < m_columns.size(); ++i ) {
7702 if ( m_iterators[i] != m_columns[i].end() ) {
7703 ++m_iterators[i];
7704 }
7705 }
7706 return *this;
7707 }
7708
7709 Columns::iterator Columns::iterator::operator++( int ) {
7710 iterator prev( *this );
7711 operator++();
7712 return prev;
7713 }
7714
7715 std::ostream& operator<<( std::ostream& os, Columns const& cols ) {
7716 bool first = true;
7717 for ( auto line : cols ) {
7718 if ( first ) {
7719 first = false;
7720 } else {
7721 os << '\n';
7722 }
7723 os << line;
7724 }
7725 return os;
7726 }
7727
7728 Columns operator+( Column const& lhs, Column const& rhs ) {
7729 Columns cols;
7730 cols += lhs;
7731 cols += rhs;
7732 return cols;
7733 }
7734 Columns operator+( Column&& lhs, Column&& rhs ) {
7735 Columns cols;
7736 cols += CATCH_MOVE( lhs );
7737 cols += CATCH_MOVE( rhs );
7738 return cols;
7739 }
7740
7741 Columns& operator+=( Columns& lhs, Column const& rhs ) {
7742 lhs.m_columns.push_back( rhs );
7743 return lhs;
7744 }
7745 Columns& operator+=( Columns& lhs, Column&& rhs ) {
7746 lhs.m_columns.push_back( CATCH_MOVE( rhs ) );
7747 return lhs;
7748 }
7749 Columns operator+( Columns const& lhs, Column const& rhs ) {
7750 auto combined( lhs );
7751 combined += rhs;
7752 return combined;
7753 }
7754 Columns operator+( Columns&& lhs, Column&& rhs ) {
7755 lhs += CATCH_MOVE( rhs );
7756 return CATCH_MOVE( lhs );
7757 }
7758
7759 } // namespace TextFlow
7760} // namespace Catch
7761
7762
7763
7764
7765#include <exception>
7766
7767namespace Catch {
7768 bool uncaught_exceptions() {
7769#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
7770 return false;
7771#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
7772 return std::uncaught_exceptions() > 0;
7773#else
7774 return std::uncaught_exception();
7775#endif
7776 }
7777} // end namespace Catch
7778
7779
7780
7781namespace Catch {
7782
7783 WildcardPattern::WildcardPattern( std::string const& pattern,
7784 CaseSensitive caseSensitivity )
7785 : m_caseSensitivity( caseSensitivity ),
7786 m_pattern( normaliseString( pattern ) )
7787 {
7788 if( startsWith( m_pattern, '*' ) ) {
7789 m_pattern = m_pattern.substr( 1 );
7790 m_wildcard = WildcardAtStart;
7791 }
7792 if( endsWith( m_pattern, '*' ) ) {
7793 m_pattern = m_pattern.substr( 0, m_pattern.size()-1 );
7794 m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
7795 }
7796 }
7797
7798 bool WildcardPattern::matches( std::string const& str ) const {
7799 switch( m_wildcard ) {
7800 case NoWildcard:
7801 return m_pattern == normaliseString( str );
7802 case WildcardAtStart:
7803 return endsWith( normaliseString( str ), m_pattern );
7804 case WildcardAtEnd:
7805 return startsWith( normaliseString( str ), m_pattern );
7806 case WildcardAtBothEnds:
7807 return contains( normaliseString( str ), m_pattern );
7808 default:
7809 CATCH_INTERNAL_ERROR( "Unknown enum" );
7810 }
7811 }
7812
7813 std::string WildcardPattern::normaliseString( std::string const& str ) const {
7814 return trim( m_caseSensitivity == CaseSensitive::No ? toLower( str ) : str );
7815 }
7816}
7817
7818
7819// Note: swapping these two includes around causes MSVC to error out
7820// while in /permissive- mode. No, I don't know why.
7821// Tested on VS 2019, 18.{3, 4}.x
7822
7823#include <cstdint>
7824#include <iomanip>
7825#include <type_traits>
7826
7827namespace Catch {
7828
7829namespace {
7830
7831 size_t trailingBytes(unsigned char c) {
7832 if ((c & 0xE0) == 0xC0) {
7833 return 2;
7834 }
7835 if ((c & 0xF0) == 0xE0) {
7836 return 3;
7837 }
7838 if ((c & 0xF8) == 0xF0) {
7839 return 4;
7840 }
7841 CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
7842 }
7843
7844 uint32_t headerValue(unsigned char c) {
7845 if ((c & 0xE0) == 0xC0) {
7846 return c & 0x1F;
7847 }
7848 if ((c & 0xF0) == 0xE0) {
7849 return c & 0x0F;
7850 }
7851 if ((c & 0xF8) == 0xF0) {
7852 return c & 0x07;
7853 }
7854 CATCH_INTERNAL_ERROR("Invalid multibyte utf-8 start byte encountered");
7855 }
7856
7857 void hexEscapeChar(std::ostream& os, unsigned char c) {
7858 std::ios_base::fmtflags f(os.flags());
7859 os << "\\x"
7860 << std::uppercase << std::hex << std::setfill('0') << std::setw(2)
7861 << static_cast<int>(c);
7862 os.flags(f);
7863 }
7864
7865 constexpr bool shouldNewline(XmlFormatting fmt) {
7866 return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Newline));
7867 }
7868
7869 constexpr bool shouldIndent(XmlFormatting fmt) {
7870 return !!(static_cast<std::underlying_type_t<XmlFormatting>>(fmt & XmlFormatting::Indent));
7871 }
7872
7873} // anonymous namespace
7874
7875 void XmlEncode::encodeTo( std::ostream& os ) const {
7876 // Apostrophe escaping not necessary if we always use " to write attributes
7877 // (see: http://www.w3.org/TR/xml/#syntax)
7878
7879 for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) {
7880 unsigned char c = static_cast<unsigned char>(m_str[idx]);
7881 switch (c) {
7882 case '<': os << "&lt;"; break;
7883 case '&': os << "&amp;"; break;
7884
7885 case '>':
7886 // See: http://www.w3.org/TR/xml/#syntax
7887 if (idx > 2 && m_str[idx - 1] == ']' && m_str[idx - 2] == ']')
7888 os << "&gt;";
7889 else
7890 os << c;
7891 break;
7892
7893 case '\"':
7894 if (m_forWhat == ForAttributes)
7895 os << "&quot;";
7896 else
7897 os << c;
7898 break;
7899
7900 default:
7901 // Check for control characters and invalid utf-8
7902
7903 // Escape control characters in standard ascii
7904 // see http://stackoverflow.com/questions/404107/why-are-control-characters-illegal-in-xml-1-0
7905 if (c < 0x09 || (c > 0x0D && c < 0x20) || c == 0x7F) {
7906 hexEscapeChar(os, c);
7907 break;
7908 }
7909
7910 // Plain ASCII: Write it to stream
7911 if (c < 0x7F) {
7912 os << c;
7913 break;
7914 }
7915
7916 // UTF-8 territory
7917 // Check if the encoding is valid and if it is not, hex escape bytes.
7918 // Important: We do not check the exact decoded values for validity, only the encoding format
7919 // First check that this bytes is a valid lead byte:
7920 // This means that it is not encoded as 1111 1XXX
7921 // Or as 10XX XXXX
7922 if (c < 0xC0 ||
7923 c >= 0xF8) {
7924 hexEscapeChar(os, c);
7925 break;
7926 }
7927
7928 auto encBytes = trailingBytes(c);
7929 // Are there enough bytes left to avoid accessing out-of-bounds memory?
7930 if (idx + encBytes - 1 >= m_str.size()) {
7931 hexEscapeChar(os, c);
7932 break;
7933 }
7934 // The header is valid, check data
7935 // The next encBytes bytes must together be a valid utf-8
7936 // This means: bitpattern 10XX XXXX and the extracted value is sane (ish)
7937 bool valid = true;
7938 uint32_t value = headerValue(c);
7939 for (std::size_t n = 1; n < encBytes; ++n) {
7940 unsigned char nc = static_cast<unsigned char>(m_str[idx + n]);
7941 valid &= ((nc & 0xC0) == 0x80);
7942 value = (value << 6) | (nc & 0x3F);
7943 }
7944
7945 if (
7946 // Wrong bit pattern of following bytes
7947 (!valid) ||
7948 // Overlong encodings
7949 (value < 0x80) ||
7950 (0x80 <= value && value < 0x800 && encBytes > 2) ||
7951 (0x800 < value && value < 0x10000 && encBytes > 3) ||
7952 // Encoded value out of range
7953 (value >= 0x110000)
7954 ) {
7955 hexEscapeChar(os, c);
7956 break;
7957 }
7958
7959 // If we got here, this is in fact a valid(ish) utf-8 sequence
7960 for (std::size_t n = 0; n < encBytes; ++n) {
7961 os << m_str[idx + n];
7962 }
7963 idx += encBytes - 1;
7964 break;
7965 }
7966 }
7967 }
7968
7969 std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode ) {
7970 xmlEncode.encodeTo( os );
7971 return os;
7972 }
7973
7974 XmlWriter::ScopedElement::ScopedElement( XmlWriter* writer, XmlFormatting fmt )
7975 : m_writer( writer ),
7976 m_fmt(fmt)
7977 {}
7978
7979 XmlWriter::ScopedElement::ScopedElement( ScopedElement&& other ) noexcept
7980 : m_writer( other.m_writer ),
7981 m_fmt(other.m_fmt)
7982 {
7983 other.m_writer = nullptr;
7984 other.m_fmt = XmlFormatting::None;
7985 }
7986 XmlWriter::ScopedElement& XmlWriter::ScopedElement::operator=( ScopedElement&& other ) noexcept {
7987 if ( m_writer ) {
7988 m_writer->endElement();
7989 }
7990 m_writer = other.m_writer;
7991 other.m_writer = nullptr;
7992 m_fmt = other.m_fmt;
7993 other.m_fmt = XmlFormatting::None;
7994 return *this;
7995 }
7996
7997
7998 XmlWriter::ScopedElement::~ScopedElement() {
7999 if (m_writer) {
8000 m_writer->endElement(m_fmt);
8001 }
8002 }
8003
8004 XmlWriter::ScopedElement&
8005 XmlWriter::ScopedElement::writeText( StringRef text, XmlFormatting fmt ) {
8006 m_writer->writeText( text, fmt );
8007 return *this;
8008 }
8009
8010 XmlWriter::ScopedElement&
8011 XmlWriter::ScopedElement::writeAttribute( StringRef name,
8012 StringRef attribute ) {
8013 m_writer->writeAttribute( name, attribute );
8014 return *this;
8015 }
8016
8017
8018 XmlWriter::XmlWriter( std::ostream& os ) : m_os( os )
8019 {
8020 writeDeclaration();
8021 }
8022
8023 XmlWriter::~XmlWriter() {
8024 while (!m_tags.empty()) {
8025 endElement();
8026 }
8027 newlineIfNecessary();
8028 }
8029
8030 XmlWriter& XmlWriter::startElement( std::string const& name, XmlFormatting fmt ) {
8031 ensureTagClosed();
8032 newlineIfNecessary();
8033 if (shouldIndent(fmt)) {
8034 m_os << m_indent;
8035 m_indent += " ";
8036 }
8037 m_os << '<' << name;
8038 m_tags.push_back( name );
8039 m_tagIsOpen = true;
8040 applyFormatting(fmt);
8041 return *this;
8042 }
8043
8044 XmlWriter::ScopedElement XmlWriter::scopedElement( std::string const& name, XmlFormatting fmt ) {
8045 ScopedElement scoped( this, fmt );
8046 startElement( name, fmt );
8047 return scoped;
8048 }
8049
8050 XmlWriter& XmlWriter::endElement(XmlFormatting fmt) {
8051 m_indent = m_indent.substr(0, m_indent.size() - 2);
8052
8053 if( m_tagIsOpen ) {
8054 m_os << "/>";
8055 m_tagIsOpen = false;
8056 } else {
8057 newlineIfNecessary();
8058 if (shouldIndent(fmt)) {
8059 m_os << m_indent;
8060 }
8061 m_os << "</" << m_tags.back() << '>';
8062 }
8063 m_os << std::flush;
8064 applyFormatting(fmt);
8065 m_tags.pop_back();
8066 return *this;
8067 }
8068
8069 XmlWriter& XmlWriter::writeAttribute( StringRef name,
8070 StringRef attribute ) {
8071 if( !name.empty() && !attribute.empty() )
8072 m_os << ' ' << name << "=\"" << XmlEncode( attribute, XmlEncode::ForAttributes ) << '"';
8073 return *this;
8074 }
8075
8076 XmlWriter& XmlWriter::writeAttribute( StringRef name, bool attribute ) {
8077 writeAttribute(name, (attribute ? "true"_sr : "false"_sr));
8078 return *this;
8079 }
8080
8081 XmlWriter& XmlWriter::writeAttribute( StringRef name,
8082 char const* attribute ) {
8083 writeAttribute( name, StringRef( attribute ) );
8084 return *this;
8085 }
8086
8087 XmlWriter& XmlWriter::writeText( StringRef text, XmlFormatting fmt ) {
8088 CATCH_ENFORCE(!m_tags.empty(), "Cannot write text as top level element");
8089 if( !text.empty() ){
8090 bool tagWasOpen = m_tagIsOpen;
8091 ensureTagClosed();
8092 if (tagWasOpen && shouldIndent(fmt)) {
8093 m_os << m_indent;
8094 }
8095 m_os << XmlEncode( text, XmlEncode::ForTextNodes );
8096 applyFormatting(fmt);
8097 }
8098 return *this;
8099 }
8100
8101 XmlWriter& XmlWriter::writeComment( StringRef text, XmlFormatting fmt ) {
8102 ensureTagClosed();
8103 if (shouldIndent(fmt)) {
8104 m_os << m_indent;
8105 }
8106 m_os << "<!-- " << text << " -->";
8107 applyFormatting(fmt);
8108 return *this;
8109 }
8110
8111 void XmlWriter::writeStylesheetRef( StringRef url ) {
8112 m_os << R"(<?xml-stylesheet type="text/xsl" href=")" << url << R"("?>)" << '\n';
8113 }
8114
8115 void XmlWriter::ensureTagClosed() {
8116 if( m_tagIsOpen ) {
8117 m_os << '>' << std::flush;
8118 newlineIfNecessary();
8119 m_tagIsOpen = false;
8120 }
8121 }
8122
8123 void XmlWriter::applyFormatting(XmlFormatting fmt) {
8124 m_needsNewline = shouldNewline(fmt);
8125 }
8126
8127 void XmlWriter::writeDeclaration() {
8128 m_os << R"(<?xml version="1.0" encoding="UTF-8"?>)" << '\n';
8129 }
8130
8131 void XmlWriter::newlineIfNecessary() {
8132 if( m_needsNewline ) {
8133 m_os << '\n' << std::flush;
8134 m_needsNewline = false;
8135 }
8136 }
8137}
8138
8139
8140
8141
8142
8143namespace Catch {
8144namespace Matchers {
8145
8146 std::string MatcherUntypedBase::toString() const {
8147 if (m_cachedToString.empty()) {
8148 m_cachedToString = describe();
8149 }
8150 return m_cachedToString;
8151 }
8152
8153 MatcherUntypedBase::~MatcherUntypedBase() = default;
8154
8155} // namespace Matchers
8156} // namespace Catch
8157
8158
8159
8160
8161namespace Catch {
8162namespace Matchers {
8163
8164 std::string IsEmptyMatcher::describe() const {
8165 return "is empty";
8166 }
8167
8168 std::string HasSizeMatcher::describe() const {
8169 ReusableStringStream sstr;
8170 sstr << "has size == " << m_target_size;
8171 return sstr.str();
8172 }
8173
8174 IsEmptyMatcher IsEmpty() {
8175 return {};
8176 }
8177
8178 HasSizeMatcher SizeIs(std::size_t sz) {
8179 return HasSizeMatcher{ sz };
8180 }
8181
8182} // end namespace Matchers
8183} // end namespace Catch
8184
8185
8186
8187namespace Catch {
8188namespace Matchers {
8189
8190bool ExceptionMessageMatcher::match(std::exception const& ex) const {
8191 return ex.what() == m_message;
8192}
8193
8194std::string ExceptionMessageMatcher::describe() const {
8195 return "exception message matches \"" + m_message + '"';
8196}
8197
8198ExceptionMessageMatcher Message(std::string const& message) {
8199 return ExceptionMessageMatcher(message);
8200}
8201
8202} // namespace Matchers
8203} // namespace Catch
8204
8205
8206
8207#include <algorithm>
8208#include <cmath>
8209#include <cstdlib>
8210#include <cstdint>
8211#include <sstream>
8212#include <iomanip>
8213#include <limits>
8214
8215
8216namespace Catch {
8217namespace {
8218
8219 template <typename FP>
8220 bool almostEqualUlps(FP lhs, FP rhs, uint64_t maxUlpDiff) {
8221 // Comparison with NaN should always be false.
8222 // This way we can rule it out before getting into the ugly details
8223 if (Catch::isnan(lhs) || Catch::isnan(rhs)) {
8224 return false;
8225 }
8226
8227 // This should also handle positive and negative zeros, infinities
8228 const auto ulpDist = ulpDistance(lhs, rhs);
8229
8230 return ulpDist <= maxUlpDiff;
8231 }
8232
8233
8234template <typename FP>
8235FP step(FP start, FP direction, uint64_t steps) {
8236 for (uint64_t i = 0; i < steps; ++i) {
8237 start = Catch::nextafter(start, direction);
8238 }
8239 return start;
8240}
8241
8242// Performs equivalent check of std::fabs(lhs - rhs) <= margin
8243// But without the subtraction to allow for INFINITY in comparison
8244bool marginComparison(double lhs, double rhs, double margin) {
8245 return (lhs + margin >= rhs) && (rhs + margin >= lhs);
8246}
8247
8248template <typename FloatingPoint>
8249void write(std::ostream& out, FloatingPoint num) {
8250 out << std::scientific
8251 << std::setprecision(std::numeric_limits<FloatingPoint>::max_digits10 - 1)
8252 << num;
8253}
8254
8255} // end anonymous namespace
8256
8257namespace Matchers {
8258namespace Detail {
8259
8260 enum class FloatingPointKind : uint8_t {
8261 Float,
8262 Double
8263 };
8264
8265} // end namespace Detail
8266
8267
8268 WithinAbsMatcher::WithinAbsMatcher(double target, double margin)
8269 :m_target{ target }, m_margin{ margin } {
8270 CATCH_ENFORCE(margin >= 0, "Invalid margin: " << margin << '.'
8271 << " Margin has to be non-negative.");
8272 }
8273
8274 // Performs equivalent check of std::fabs(lhs - rhs) <= margin
8275 // But without the subtraction to allow for INFINITY in comparison
8276 bool WithinAbsMatcher::match(double const& matchee) const {
8277 return (matchee + m_margin >= m_target) && (m_target + m_margin >= matchee);
8278 }
8279
8280 std::string WithinAbsMatcher::describe() const {
8281 return "is within " + ::Catch::Detail::stringify(m_margin) + " of " + ::Catch::Detail::stringify(m_target);
8282 }
8283
8284
8285 WithinUlpsMatcher::WithinUlpsMatcher(double target, uint64_t ulps, Detail::FloatingPointKind baseType)
8286 :m_target{ target }, m_ulps{ ulps }, m_type{ baseType } {
8287 CATCH_ENFORCE(m_type == Detail::FloatingPointKind::Double
8288 || m_ulps < (std::numeric_limits<uint32_t>::max)(),
8289 "Provided ULP is impossibly large for a float comparison.");
8290 CATCH_ENFORCE( std::numeric_limits<double>::is_iec559,
8291 "WithinUlp matcher only supports platforms with "
8292 "IEEE-754 compatible floating point representation" );
8293 }
8294
8295#if defined(__clang__)
8296#pragma clang diagnostic push
8297// Clang <3.5 reports on the default branch in the switch below
8298#pragma clang diagnostic ignored "-Wunreachable-code"
8299#endif
8300
8301 bool WithinUlpsMatcher::match(double const& matchee) const {
8302 switch (m_type) {
8303 case Detail::FloatingPointKind::Float:
8304 return almostEqualUlps<float>(static_cast<float>(matchee), static_cast<float>(m_target), m_ulps);
8305 case Detail::FloatingPointKind::Double:
8306 return almostEqualUlps<double>(matchee, m_target, m_ulps);
8307 default:
8308 CATCH_INTERNAL_ERROR( "Unknown Detail::FloatingPointKind value" );
8309 }
8310 }
8311
8312#if defined(__clang__)
8313#pragma clang diagnostic pop
8314#endif
8315
8316 std::string WithinUlpsMatcher::describe() const {
8317 std::stringstream ret;
8318
8319 ret << "is within " << m_ulps << " ULPs of ";
8320
8321 if (m_type == Detail::FloatingPointKind::Float) {
8322 write(ret, static_cast<float>(m_target));
8323 ret << 'f';
8324 } else {
8325 write(ret, m_target);
8326 }
8327
8328 ret << " ([";
8329 if (m_type == Detail::FloatingPointKind::Double) {
8330 write( ret,
8331 step( m_target,
8332 -std::numeric_limits<double>::infinity(),
8333 m_ulps ) );
8334 ret << ", ";
8335 write( ret,
8336 step( m_target,
8337 std::numeric_limits<double>::infinity(),
8338 m_ulps ) );
8339 } else {
8340 // We have to cast INFINITY to float because of MinGW, see #1782
8341 write( ret,
8342 step( static_cast<float>( m_target ),
8343 -std::numeric_limits<float>::infinity(),
8344 m_ulps ) );
8345 ret << ", ";
8346 write( ret,
8347 step( static_cast<float>( m_target ),
8348 std::numeric_limits<float>::infinity(),
8349 m_ulps ) );
8350 }
8351 ret << "])";
8352
8353 return ret.str();
8354 }
8355
8356 WithinRelMatcher::WithinRelMatcher(double target, double epsilon):
8357 m_target(target),
8358 m_epsilon(epsilon){
8359 CATCH_ENFORCE(m_epsilon >= 0., "Relative comparison with epsilon < 0 does not make sense.");
8360 CATCH_ENFORCE(m_epsilon < 1., "Relative comparison with epsilon >= 1 does not make sense.");
8361 }
8362
8363 bool WithinRelMatcher::match(double const& matchee) const {
8364 const auto relMargin = m_epsilon * (std::max)(std::fabs(matchee), std::fabs(m_target));
8365 return marginComparison(matchee, m_target,
8366 std::isinf(relMargin)? 0 : relMargin);
8367 }
8368
8369 std::string WithinRelMatcher::describe() const {
8370 Catch::ReusableStringStream sstr;
8371 sstr << "and " << ::Catch::Detail::stringify(m_target) << " are within " << m_epsilon * 100. << "% of each other";
8372 return sstr.str();
8373 }
8374
8375
8376WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff) {
8377 return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Double);
8378}
8379
8380WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff) {
8381 return WithinUlpsMatcher(target, maxUlpDiff, Detail::FloatingPointKind::Float);
8382}
8383
8384WithinAbsMatcher WithinAbs(double target, double margin) {
8385 return WithinAbsMatcher(target, margin);
8386}
8387
8388WithinRelMatcher WithinRel(double target, double eps) {
8389 return WithinRelMatcher(target, eps);
8390}
8391
8392WithinRelMatcher WithinRel(double target) {
8393 return WithinRelMatcher(target, std::numeric_limits<double>::epsilon() * 100);
8394}
8395
8396WithinRelMatcher WithinRel(float target, float eps) {
8397 return WithinRelMatcher(target, eps);
8398}
8399
8400WithinRelMatcher WithinRel(float target) {
8401 return WithinRelMatcher(target, std::numeric_limits<float>::epsilon() * 100);
8402}
8403
8404
8405
8406bool IsNaNMatcher::match( double const& matchee ) const {
8407 return std::isnan( matchee );
8408}
8409
8410std::string IsNaNMatcher::describe() const {
8411 using namespace std::string_literals;
8412 return "is NaN"s;
8413}
8414
8415IsNaNMatcher IsNaN() { return IsNaNMatcher(); }
8416
8417 } // namespace Matchers
8418} // namespace Catch
8419
8420
8421
8422
8423std::string Catch::Matchers::Detail::finalizeDescription(const std::string& desc) {
8424 if (desc.empty()) {
8425 return "matches undescribed predicate";
8426 } else {
8427 return "matches predicate: \"" + desc + '"';
8428 }
8429}
8430
8431
8432
8433namespace Catch {
8434 namespace Matchers {
8435 std::string AllTrueMatcher::describe() const { return "contains only true"; }
8436
8437 AllTrueMatcher AllTrue() { return AllTrueMatcher{}; }
8438
8439 std::string NoneTrueMatcher::describe() const { return "contains no true"; }
8440
8441 NoneTrueMatcher NoneTrue() { return NoneTrueMatcher{}; }
8442
8443 std::string AnyTrueMatcher::describe() const { return "contains at least one true"; }
8444
8445 AnyTrueMatcher AnyTrue() { return AnyTrueMatcher{}; }
8446 } // namespace Matchers
8447} // namespace Catch
8448
8449
8450
8451#include <regex>
8452
8453namespace Catch {
8454namespace Matchers {
8455
8456 CasedString::CasedString( std::string const& str, CaseSensitive caseSensitivity )
8457 : m_caseSensitivity( caseSensitivity ),
8458 m_str( adjustString( str ) )
8459 {}
8460 std::string CasedString::adjustString( std::string const& str ) const {
8461 return m_caseSensitivity == CaseSensitive::No
8462 ? toLower( str )
8463 : str;
8464 }
8465 StringRef CasedString::caseSensitivitySuffix() const {
8466 return m_caseSensitivity == CaseSensitive::Yes
8467 ? StringRef()
8468 : " (case insensitive)"_sr;
8469 }
8470
8471
8472 StringMatcherBase::StringMatcherBase( StringRef operation, CasedString const& comparator )
8473 : m_comparator( comparator ),
8474 m_operation( operation ) {
8475 }
8476
8477 std::string StringMatcherBase::describe() const {
8478 std::string description;
8479 description.reserve(5 + m_operation.size() + m_comparator.m_str.size() +
8480 m_comparator.caseSensitivitySuffix().size());
8481 description += m_operation;
8482 description += ": \"";
8483 description += m_comparator.m_str;
8484 description += '"';
8485 description += m_comparator.caseSensitivitySuffix();
8486 return description;
8487 }
8488
8489 StringEqualsMatcher::StringEqualsMatcher( CasedString const& comparator ) : StringMatcherBase( "equals"_sr, comparator ) {}
8490
8491 bool StringEqualsMatcher::match( std::string const& source ) const {
8492 return m_comparator.adjustString( source ) == m_comparator.m_str;
8493 }
8494
8495
8496 StringContainsMatcher::StringContainsMatcher( CasedString const& comparator ) : StringMatcherBase( "contains"_sr, comparator ) {}
8497
8498 bool StringContainsMatcher::match( std::string const& source ) const {
8499 return contains( m_comparator.adjustString( source ), m_comparator.m_str );
8500 }
8501
8502
8503 StartsWithMatcher::StartsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "starts with"_sr, comparator ) {}
8504
8505 bool StartsWithMatcher::match( std::string const& source ) const {
8506 return startsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8507 }
8508
8509
8510 EndsWithMatcher::EndsWithMatcher( CasedString const& comparator ) : StringMatcherBase( "ends with"_sr, comparator ) {}
8511
8512 bool EndsWithMatcher::match( std::string const& source ) const {
8513 return endsWith( m_comparator.adjustString( source ), m_comparator.m_str );
8514 }
8515
8516
8517
8518 RegexMatcher::RegexMatcher(std::string regex, CaseSensitive caseSensitivity): m_regex(CATCH_MOVE(regex)), m_caseSensitivity(caseSensitivity) {}
8519
8520 bool RegexMatcher::match(std::string const& matchee) const {
8521 auto flags = std::regex::ECMAScript; // ECMAScript is the default syntax option anyway
8522 if (m_caseSensitivity == CaseSensitive::No) {
8523 flags |= std::regex::icase;
8524 }
8525 auto reg = std::regex(m_regex, flags);
8526 return std::regex_match(matchee, reg);
8527 }
8528
8529 std::string RegexMatcher::describe() const {
8530 return "matches " + ::Catch::Detail::stringify(m_regex) + ((m_caseSensitivity == CaseSensitive::Yes)? " case sensitively" : " case insensitively");
8531 }
8532
8533
8534 StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity ) {
8535 return StringEqualsMatcher( CasedString( str, caseSensitivity) );
8536 }
8537 StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity ) {
8538 return StringContainsMatcher( CasedString( str, caseSensitivity) );
8539 }
8540 EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8541 return EndsWithMatcher( CasedString( str, caseSensitivity) );
8542 }
8543 StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity ) {
8544 return StartsWithMatcher( CasedString( str, caseSensitivity) );
8545 }
8546
8547 RegexMatcher Matches(std::string const& regex, CaseSensitive caseSensitivity) {
8548 return RegexMatcher(regex, caseSensitivity);
8549 }
8550
8551} // namespace Matchers
8552} // namespace Catch
8553
8554
8555
8556namespace Catch {
8557namespace Matchers {
8558 MatcherGenericBase::~MatcherGenericBase() = default;
8559
8560 namespace Detail {
8561
8562 std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end) {
8563 std::string description;
8564 std::size_t combined_size = 4;
8565 for ( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8566 combined_size += desc->size();
8567 }
8568 combined_size += static_cast<size_t>(descriptions_end - descriptions_begin - 1) * combine.size();
8569
8570 description.reserve(combined_size);
8571
8572 description += "( ";
8573 bool first = true;
8574 for( auto desc = descriptions_begin; desc != descriptions_end; ++desc ) {
8575 if( first )
8576 first = false;
8577 else
8578 description += combine;
8579 description += *desc;
8580 }
8581 description += " )";
8582 return description;
8583 }
8584
8585 } // namespace Detail
8586} // namespace Matchers
8587} // namespace Catch
8588
8589
8590
8591
8592namespace Catch {
8593
8594 // This is the general overload that takes a any string matcher
8595 // There is another overload, in catch_assertionhandler.h/.cpp, that only takes a string and infers
8596 // the Equals matcher (so the header does not mention matchers)
8597 void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher ) {
8598 std::string exceptionMessage = Catch::translateActiveException();
8599 MatchExpr<std::string, StringMatcher const&> expr( CATCH_MOVE(exceptionMessage), matcher );
8600 handler.handleExpr( expr );
8601 }
8602
8603} // namespace Catch
8604
8605
8606
8607#include <ostream>
8608
8609namespace Catch {
8610
8611 AutomakeReporter::~AutomakeReporter() = default;
8612
8613 void AutomakeReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
8614 // Possible values to emit are PASS, XFAIL, SKIP, FAIL, XPASS and ERROR.
8615 m_stream << ":test-result: ";
8616 if ( _testCaseStats.totals.testCases.skipped > 0 ) {
8617 m_stream << "SKIP";
8618 } else if (_testCaseStats.totals.assertions.allPassed()) {
8619 m_stream << "PASS";
8620 } else if (_testCaseStats.totals.assertions.allOk()) {
8621 m_stream << "XFAIL";
8622 } else {
8623 m_stream << "FAIL";
8624 }
8625 m_stream << ' ' << _testCaseStats.testInfo->name << '\n';
8626 StreamingReporterBase::testCaseEnded(_testCaseStats);
8627 }
8628
8629 void AutomakeReporter::skipTest(TestCaseInfo const& testInfo) {
8630 m_stream << ":test-result: SKIP " << testInfo.name << '\n';
8631 }
8632
8633} // end namespace Catch
8634
8635
8636
8637
8638
8639
8640namespace Catch {
8641 ReporterBase::ReporterBase( ReporterConfig&& config ):
8642 IEventListener( config.fullConfig() ),
8643 m_wrapped_stream( CATCH_MOVE(config).takeStream() ),
8644 m_stream( m_wrapped_stream->stream() ),
8645 m_colour( makeColourImpl( config.colourMode(), m_wrapped_stream.get() ) ),
8646 m_customOptions( config.customOptions() )
8647 {}
8648
8649 ReporterBase::~ReporterBase() = default;
8650
8651 void ReporterBase::listReporters(
8652 std::vector<ReporterDescription> const& descriptions ) {
8653 defaultListReporters(m_stream, descriptions, m_config->verbosity());
8654 }
8655
8656 void ReporterBase::listListeners(
8657 std::vector<ListenerDescription> const& descriptions ) {
8658 defaultListListeners( m_stream, descriptions );
8659 }
8660
8661 void ReporterBase::listTests(std::vector<TestCaseHandle> const& tests) {
8662 defaultListTests(m_stream,
8663 m_colour.get(),
8664 tests,
8665 m_config->hasTestFilters(),
8666 m_config->verbosity());
8667 }
8668
8669 void ReporterBase::listTags(std::vector<TagInfo> const& tags) {
8670 defaultListTags( m_stream, tags, m_config->hasTestFilters() );
8671 }
8672
8673} // namespace Catch
8674
8675
8676
8677
8678#include <ostream>
8679
8680namespace Catch {
8681namespace {
8682
8683 // Colour::LightGrey
8684 static constexpr Colour::Code compactDimColour = Colour::FileName;
8685
8686#ifdef CATCH_PLATFORM_MAC
8687 static constexpr Catch::StringRef compactFailedString = "FAILED"_sr;
8688 static constexpr Catch::StringRef compactPassedString = "PASSED"_sr;
8689#else
8690 static constexpr Catch::StringRef compactFailedString = "failed"_sr;
8691 static constexpr Catch::StringRef compactPassedString = "passed"_sr;
8692#endif
8693
8694// Implementation of CompactReporter formatting
8695class AssertionPrinter {
8696public:
8697 AssertionPrinter& operator= (AssertionPrinter const&) = delete;
8698 AssertionPrinter(AssertionPrinter const&) = delete;
8699 AssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages, ColourImpl* colourImpl_)
8700 : stream(_stream)
8701 , result(_stats.assertionResult)
8702 , messages(_stats.infoMessages)
8703 , itMessage(_stats.infoMessages.begin())
8704 , printInfoMessages(_printInfoMessages)
8705 , colourImpl(colourImpl_)
8706 {}
8707
8708 void print() {
8709 printSourceInfo();
8710
8711 itMessage = messages.begin();
8712
8713 switch (result.getResultType()) {
8714 case ResultWas::Ok:
8715 printResultType(Colour::ResultSuccess, compactPassedString);
8716 printOriginalExpression();
8717 printReconstructedExpression();
8718 if (!result.hasExpression())
8719 printRemainingMessages(Colour::None);
8720 else
8721 printRemainingMessages();
8722 break;
8723 case ResultWas::ExpressionFailed:
8724 if (result.isOk())
8725 printResultType(Colour::ResultSuccess, compactFailedString + " - but was ok"_sr);
8726 else
8727 printResultType(Colour::Error, compactFailedString);
8728 printOriginalExpression();
8729 printReconstructedExpression();
8730 printRemainingMessages();
8731 break;
8732 case ResultWas::ThrewException:
8733 printResultType(Colour::Error, compactFailedString);
8734 printIssue("unexpected exception with message:");
8735 printMessage();
8736 printExpressionWas();
8737 printRemainingMessages();
8738 break;
8739 case ResultWas::FatalErrorCondition:
8740 printResultType(Colour::Error, compactFailedString);
8741 printIssue("fatal error condition with message:");
8742 printMessage();
8743 printExpressionWas();
8744 printRemainingMessages();
8745 break;
8746 case ResultWas::DidntThrowException:
8747 printResultType(Colour::Error, compactFailedString);
8748 printIssue("expected exception, got none");
8749 printExpressionWas();
8750 printRemainingMessages();
8751 break;
8752 case ResultWas::Info:
8753 printResultType(Colour::None, "info"_sr);
8754 printMessage();
8755 printRemainingMessages();
8756 break;
8757 case ResultWas::Warning:
8758 printResultType(Colour::None, "warning"_sr);
8759 printMessage();
8760 printRemainingMessages();
8761 break;
8762 case ResultWas::ExplicitFailure:
8763 printResultType(Colour::Error, compactFailedString);
8764 printIssue("explicitly");
8765 printRemainingMessages(Colour::None);
8766 break;
8767 case ResultWas::ExplicitSkip:
8768 printResultType(Colour::Skip, "skipped"_sr);
8769 printMessage();
8770 printRemainingMessages();
8771 break;
8772 // These cases are here to prevent compiler warnings
8773 case ResultWas::Unknown:
8774 case ResultWas::FailureBit:
8775 case ResultWas::Exception:
8776 printResultType(Colour::Error, "** internal error **");
8777 break;
8778 }
8779 }
8780
8781private:
8782 void printSourceInfo() const {
8783 stream << colourImpl->guardColour( Colour::FileName )
8784 << result.getSourceInfo() << ':';
8785 }
8786
8787 void printResultType(Colour::Code colour, StringRef passOrFail) const {
8788 if (!passOrFail.empty()) {
8789 stream << colourImpl->guardColour(colour) << ' ' << passOrFail;
8790 stream << ':';
8791 }
8792 }
8793
8794 void printIssue(char const* issue) const {
8795 stream << ' ' << issue;
8796 }
8797
8798 void printExpressionWas() {
8799 if (result.hasExpression()) {
8800 stream << ';';
8801 {
8802 stream << colourImpl->guardColour(compactDimColour) << " expression was:";
8803 }
8804 printOriginalExpression();
8805 }
8806 }
8807
8808 void printOriginalExpression() const {
8809 if (result.hasExpression()) {
8810 stream << ' ' << result.getExpression();
8811 }
8812 }
8813
8814 void printReconstructedExpression() const {
8815 if (result.hasExpandedExpression()) {
8816 stream << colourImpl->guardColour(compactDimColour) << " for: ";
8817 stream << result.getExpandedExpression();
8818 }
8819 }
8820
8821 void printMessage() {
8822 if (itMessage != messages.end()) {
8823 stream << " '" << itMessage->message << '\'';
8824 ++itMessage;
8825 }
8826 }
8827
8828 void printRemainingMessages(Colour::Code colour = compactDimColour) {
8829 if (itMessage == messages.end())
8830 return;
8831
8832 const auto itEnd = messages.cend();
8833 const auto N = static_cast<std::size_t>(itEnd - itMessage);
8834
8835 stream << colourImpl->guardColour( colour ) << " with "
8836 << pluralise( N, "message"_sr ) << ':';
8837
8838 while (itMessage != itEnd) {
8839 // If this assertion is a warning ignore any INFO messages
8840 if (printInfoMessages || itMessage->type != ResultWas::Info) {
8841 printMessage();
8842 if (itMessage != itEnd) {
8843 stream << colourImpl->guardColour(compactDimColour) << " and";
8844 }
8845 continue;
8846 }
8847 ++itMessage;
8848 }
8849 }
8850
8851private:
8852 std::ostream& stream;
8853 AssertionResult const& result;
8854 std::vector<MessageInfo> const& messages;
8855 std::vector<MessageInfo>::const_iterator itMessage;
8856 bool printInfoMessages;
8857 ColourImpl* colourImpl;
8858};
8859
8860} // anon namespace
8861
8862 std::string CompactReporter::getDescription() {
8863 return "Reports test results on a single line, suitable for IDEs";
8864 }
8865
8866 void CompactReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
8867 m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
8868 }
8869
8870 void CompactReporter::testRunStarting( TestRunInfo const& ) {
8871 if ( m_config->testSpec().hasFilters() ) {
8872 m_stream << m_colour->guardColour( Colour::BrightYellow )
8873 << "Filters: "
8874 << m_config->testSpec()
8875 << '\n';
8876 }
8877 m_stream << "RNG seed: " << getSeed() << '\n';
8878 }
8879
8880 void CompactReporter::assertionEnded( AssertionStats const& _assertionStats ) {
8881 AssertionResult const& result = _assertionStats.assertionResult;
8882
8883 bool printInfoMessages = true;
8884
8885 // Drop out if result was successful and we're not printing those
8886 if( !m_config->includeSuccessfulResults() && result.isOk() ) {
8887 if( result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip )
8888 return;
8889 printInfoMessages = false;
8890 }
8891
8892 AssertionPrinter printer( m_stream, _assertionStats, printInfoMessages, m_colour.get() );
8893 printer.print();
8894
8895 m_stream << '\n' << std::flush;
8896 }
8897
8898 void CompactReporter::sectionEnded(SectionStats const& _sectionStats) {
8899 double dur = _sectionStats.durationInSeconds;
8900 if ( shouldShowDuration( *m_config, dur ) ) {
8901 m_stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
8902 }
8903 }
8904
8905 void CompactReporter::testRunEnded( TestRunStats const& _testRunStats ) {
8906 printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
8907 m_stream << "\n\n" << std::flush;
8908 StreamingReporterBase::testRunEnded( _testRunStats );
8909 }
8910
8911 CompactReporter::~CompactReporter() = default;
8912
8913} // end namespace Catch
8914
8915
8916
8917
8918#include <cstdio>
8919
8920#if defined(_MSC_VER)
8921#pragma warning(push)
8922#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
8923 // Note that 4062 (not all labels are handled and default is missing) is enabled
8924#endif
8925
8926#if defined(__clang__)
8927# pragma clang diagnostic push
8928// For simplicity, benchmarking-only helpers are always enabled
8929# pragma clang diagnostic ignored "-Wunused-function"
8930#endif
8931
8932
8933
8934namespace Catch {
8935
8936namespace {
8937
8938// Formatter impl for ConsoleReporter
8939class ConsoleAssertionPrinter {
8940public:
8941 ConsoleAssertionPrinter& operator= (ConsoleAssertionPrinter const&) = delete;
8942 ConsoleAssertionPrinter(ConsoleAssertionPrinter const&) = delete;
8943 ConsoleAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, ColourImpl* colourImpl_, bool _printInfoMessages)
8944 : stream(_stream),
8945 stats(_stats),
8946 result(_stats.assertionResult),
8947 colour(Colour::None),
8948 messages(_stats.infoMessages),
8949 colourImpl(colourImpl_),
8950 printInfoMessages(_printInfoMessages) {
8951 switch (result.getResultType()) {
8952 case ResultWas::Ok:
8953 colour = Colour::Success;
8954 passOrFail = "PASSED"_sr;
8955 //if( result.hasMessage() )
8956 if (messages.size() == 1)
8957 messageLabel = "with message"_sr;
8958 if (messages.size() > 1)
8959 messageLabel = "with messages"_sr;
8960 break;
8961 case ResultWas::ExpressionFailed:
8962 if (result.isOk()) {
8963 colour = Colour::Success;
8964 passOrFail = "FAILED - but was ok"_sr;
8965 } else {
8966 colour = Colour::Error;
8967 passOrFail = "FAILED"_sr;
8968 }
8969 if (messages.size() == 1)
8970 messageLabel = "with message"_sr;
8971 if (messages.size() > 1)
8972 messageLabel = "with messages"_sr;
8973 break;
8974 case ResultWas::ThrewException:
8975 colour = Colour::Error;
8976 passOrFail = "FAILED"_sr;
8977 // todo switch
8978 switch (messages.size()) { case 0:
8979 messageLabel = "due to unexpected exception with "_sr;
8980 break;
8981 case 1:
8982 messageLabel = "due to unexpected exception with message"_sr;
8983 break;
8984 default:
8985 messageLabel = "due to unexpected exception with messages"_sr;
8986 break;
8987 }
8988 break;
8989 case ResultWas::FatalErrorCondition:
8990 colour = Colour::Error;
8991 passOrFail = "FAILED"_sr;
8992 messageLabel = "due to a fatal error condition"_sr;
8993 break;
8994 case ResultWas::DidntThrowException:
8995 colour = Colour::Error;
8996 passOrFail = "FAILED"_sr;
8997 messageLabel = "because no exception was thrown where one was expected"_sr;
8998 break;
8999 case ResultWas::Info:
9000 messageLabel = "info"_sr;
9001 break;
9002 case ResultWas::Warning:
9003 messageLabel = "warning"_sr;
9004 break;
9005 case ResultWas::ExplicitFailure:
9006 passOrFail = "FAILED"_sr;
9007 colour = Colour::Error;
9008 if (messages.size() == 1)
9009 messageLabel = "explicitly with message"_sr;
9010 if (messages.size() > 1)
9011 messageLabel = "explicitly with messages"_sr;
9012 break;
9013 case ResultWas::ExplicitSkip:
9014 colour = Colour::Skip;
9015 passOrFail = "SKIPPED"_sr;
9016 if (messages.size() == 1)
9017 messageLabel = "explicitly with message"_sr;
9018 if (messages.size() > 1)
9019 messageLabel = "explicitly with messages"_sr;
9020 break;
9021 // These cases are here to prevent compiler warnings
9022 case ResultWas::Unknown:
9023 case ResultWas::FailureBit:
9024 case ResultWas::Exception:
9025 passOrFail = "** internal error **"_sr;
9026 colour = Colour::Error;
9027 break;
9028 }
9029 }
9030
9031 void print() const {
9032 printSourceInfo();
9033 if (stats.totals.assertions.total() > 0) {
9034 printResultType();
9035 printOriginalExpression();
9036 printReconstructedExpression();
9037 } else {
9038 stream << '\n';
9039 }
9040 printMessage();
9041 }
9042
9043private:
9044 void printResultType() const {
9045 if (!passOrFail.empty()) {
9046 stream << colourImpl->guardColour(colour) << passOrFail << ":\n";
9047 }
9048 }
9049 void printOriginalExpression() const {
9050 if (result.hasExpression()) {
9051 stream << colourImpl->guardColour( Colour::OriginalExpression )
9052 << " " << result.getExpressionInMacro() << '\n';
9053 }
9054 }
9055 void printReconstructedExpression() const {
9056 if (result.hasExpandedExpression()) {
9057 stream << "with expansion:\n";
9058 stream << colourImpl->guardColour( Colour::ReconstructedExpression )
9059 << TextFlow::Column( result.getExpandedExpression() )
9060 .indent( 2 )
9061 << '\n';
9062 }
9063 }
9064 void printMessage() const {
9065 if (!messageLabel.empty())
9066 stream << messageLabel << ':' << '\n';
9067 for (auto const& msg : messages) {
9068 // If this assertion is a warning ignore any INFO messages
9069 if (printInfoMessages || msg.type != ResultWas::Info)
9070 stream << TextFlow::Column(msg.message).indent(2) << '\n';
9071 }
9072 }
9073 void printSourceInfo() const {
9074 stream << colourImpl->guardColour( Colour::FileName )
9075 << result.getSourceInfo() << ": ";
9076 }
9077
9078 std::ostream& stream;
9079 AssertionStats const& stats;
9080 AssertionResult const& result;
9081 Colour::Code colour;
9082 StringRef passOrFail;
9083 StringRef messageLabel;
9084 std::vector<MessageInfo> const& messages;
9085 ColourImpl* colourImpl;
9086 bool printInfoMessages;
9087};
9088
9089std::size_t makeRatio( std::uint64_t number, std::uint64_t total ) {
9090 const auto ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number / total : 0;
9091 return (ratio == 0 && number > 0) ? 1 : static_cast<std::size_t>(ratio);
9092}
9093
9094std::size_t&
9095findMax( std::size_t& i, std::size_t& j, std::size_t& k, std::size_t& l ) {
9096 if (i > j && i > k && i > l)
9097 return i;
9098 else if (j > k && j > l)
9099 return j;
9100 else if (k > l)
9101 return k;
9102 else
9103 return l;
9104}
9105
9106struct ColumnBreak {};
9107struct RowBreak {};
9108struct OutputFlush {};
9109
9110class Duration {
9111 enum class Unit {
9112 Auto,
9113 Nanoseconds,
9114 Microseconds,
9115 Milliseconds,
9116 Seconds,
9117 Minutes
9118 };
9119 static const uint64_t s_nanosecondsInAMicrosecond = 1000;
9120 static const uint64_t s_nanosecondsInAMillisecond = 1000 * s_nanosecondsInAMicrosecond;
9121 static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond;
9122 static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond;
9123
9124 double m_inNanoseconds;
9125 Unit m_units;
9126
9127public:
9128 explicit Duration(double inNanoseconds, Unit units = Unit::Auto)
9129 : m_inNanoseconds(inNanoseconds),
9130 m_units(units) {
9131 if (m_units == Unit::Auto) {
9132 if (m_inNanoseconds < s_nanosecondsInAMicrosecond)
9133 m_units = Unit::Nanoseconds;
9134 else if (m_inNanoseconds < s_nanosecondsInAMillisecond)
9135 m_units = Unit::Microseconds;
9136 else if (m_inNanoseconds < s_nanosecondsInASecond)
9137 m_units = Unit::Milliseconds;
9138 else if (m_inNanoseconds < s_nanosecondsInAMinute)
9139 m_units = Unit::Seconds;
9140 else
9141 m_units = Unit::Minutes;
9142 }
9143
9144 }
9145
9146 auto value() const -> double {
9147 switch (m_units) {
9148 case Unit::Microseconds:
9149 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMicrosecond);
9150 case Unit::Milliseconds:
9151 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMillisecond);
9152 case Unit::Seconds:
9153 return m_inNanoseconds / static_cast<double>(s_nanosecondsInASecond);
9154 case Unit::Minutes:
9155 return m_inNanoseconds / static_cast<double>(s_nanosecondsInAMinute);
9156 default:
9157 return m_inNanoseconds;
9158 }
9159 }
9160 StringRef unitsAsString() const {
9161 switch (m_units) {
9162 case Unit::Nanoseconds:
9163 return "ns"_sr;
9164 case Unit::Microseconds:
9165 return "us"_sr;
9166 case Unit::Milliseconds:
9167 return "ms"_sr;
9168 case Unit::Seconds:
9169 return "s"_sr;
9170 case Unit::Minutes:
9171 return "m"_sr;
9172 default:
9173 return "** internal error **"_sr;
9174 }
9175
9176 }
9177 friend auto operator << (std::ostream& os, Duration const& duration) -> std::ostream& {
9178 return os << duration.value() << ' ' << duration.unitsAsString();
9179 }
9180};
9181} // end anon namespace
9182
9183enum class Justification { Left, Right };
9184
9185struct ColumnInfo {
9186 std::string name;
9187 std::size_t width;
9188 Justification justification;
9189};
9190
9191class TablePrinter {
9192 std::ostream& m_os;
9193 std::vector<ColumnInfo> m_columnInfos;
9194 ReusableStringStream m_oss;
9195 int m_currentColumn = -1;
9196 bool m_isOpen = false;
9197
9198public:
9199 TablePrinter( std::ostream& os, std::vector<ColumnInfo> columnInfos )
9200 : m_os( os ),
9201 m_columnInfos( CATCH_MOVE( columnInfos ) ) {}
9202
9203 auto columnInfos() const -> std::vector<ColumnInfo> const& {
9204 return m_columnInfos;
9205 }
9206
9207 void open() {
9208 if (!m_isOpen) {
9209 m_isOpen = true;
9210 *this << RowBreak();
9211
9212 TextFlow::Columns headerCols;
9213 for (auto const& info : m_columnInfos) {
9214 assert(info.width > 2);
9215 headerCols += TextFlow::Column(info.name).width(info.width - 2);
9216 headerCols += TextFlow::Spacer( 2 );
9217 }
9218 m_os << headerCols << '\n';
9219
9220 m_os << lineOfChars('-') << '\n';
9221 }
9222 }
9223 void close() {
9224 if (m_isOpen) {
9225 *this << RowBreak();
9226 m_os << '\n' << std::flush;
9227 m_isOpen = false;
9228 }
9229 }
9230
9231 template<typename T>
9232 friend TablePrinter& operator<< (TablePrinter& tp, T const& value) {
9233 tp.m_oss << value;
9234 return tp;
9235 }
9236
9237 friend TablePrinter& operator<< (TablePrinter& tp, ColumnBreak) {
9238 auto colStr = tp.m_oss.str();
9239 const auto strSize = colStr.size();
9240 tp.m_oss.str("");
9241 tp.open();
9242 if (tp.m_currentColumn == static_cast<int>(tp.m_columnInfos.size() - 1)) {
9243 tp.m_currentColumn = -1;
9244 tp.m_os << '\n';
9245 }
9246 tp.m_currentColumn++;
9247
9248 auto colInfo = tp.m_columnInfos[tp.m_currentColumn];
9249 auto padding = (strSize + 1 < colInfo.width)
9250 ? std::string(colInfo.width - (strSize + 1), ' ')
9251 : std::string();
9252 if (colInfo.justification == Justification::Left)
9253 tp.m_os << colStr << padding << ' ';
9254 else
9255 tp.m_os << padding << colStr << ' ';
9256 return tp;
9257 }
9258
9259 friend TablePrinter& operator<< (TablePrinter& tp, RowBreak) {
9260 if (tp.m_currentColumn > 0) {
9261 tp.m_os << '\n';
9262 tp.m_currentColumn = -1;
9263 }
9264 return tp;
9265 }
9266
9267 friend TablePrinter& operator<<(TablePrinter& tp, OutputFlush) {
9268 tp.m_os << std::flush;
9269 return tp;
9270 }
9271};
9272
9273ConsoleReporter::ConsoleReporter(ReporterConfig&& config):
9274 StreamingReporterBase( CATCH_MOVE( config ) ),
9275 m_tablePrinter(Detail::make_unique<TablePrinter>(m_stream,
9276 [&config]() -> std::vector<ColumnInfo> {
9277 if (config.fullConfig()->benchmarkNoAnalysis())
9278 {
9279 return{
9280 { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9281 { " samples", 14, Justification::Right },
9282 { " iterations", 14, Justification::Right },
9283 { " mean", 14, Justification::Right }
9284 };
9285 }
9286 else
9287 {
9288 return{
9289 { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, Justification::Left },
9290 { "samples mean std dev", 14, Justification::Right },
9291 { "iterations low mean low std dev", 14, Justification::Right },
9292 { "est run time high mean high std dev", 14, Justification::Right }
9293 };
9294 }
9295 }())) {}
9296ConsoleReporter::~ConsoleReporter() = default;
9297
9298std::string ConsoleReporter::getDescription() {
9299 return "Reports test results as plain lines of text";
9300}
9301
9302void ConsoleReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
9303 m_stream << "No test cases matched '" << unmatchedSpec << "'\n";
9304}
9305
9306void ConsoleReporter::reportInvalidTestSpec( StringRef arg ) {
9307 m_stream << "Invalid Filter: " << arg << '\n';
9308}
9309
9310void ConsoleReporter::assertionStarting(AssertionInfo const&) {}
9311
9312void ConsoleReporter::assertionEnded(AssertionStats const& _assertionStats) {
9313 AssertionResult const& result = _assertionStats.assertionResult;
9314
9315 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
9316
9317 // Drop out if result was successful but we're not printing them.
9318 // TODO: Make configurable whether skips should be printed
9319 if (!includeResults && result.getResultType() != ResultWas::Warning && result.getResultType() != ResultWas::ExplicitSkip)
9320 return;
9321
9322 lazyPrint();
9323
9324 ConsoleAssertionPrinter printer(m_stream, _assertionStats, m_colour.get(), includeResults);
9325 printer.print();
9326 m_stream << '\n' << std::flush;
9327}
9328
9329void ConsoleReporter::sectionStarting(SectionInfo const& _sectionInfo) {
9330 m_tablePrinter->close();
9331 m_headerPrinted = false;
9332 StreamingReporterBase::sectionStarting(_sectionInfo);
9333}
9334void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) {
9335 m_tablePrinter->close();
9336 if (_sectionStats.missingAssertions) {
9337 lazyPrint();
9338 auto guard =
9339 m_colour->guardColour( Colour::ResultError ).engage( m_stream );
9340 if (m_sectionStack.size() > 1)
9341 m_stream << "\nNo assertions in section";
9342 else
9343 m_stream << "\nNo assertions in test case";
9344 m_stream << " '" << _sectionStats.sectionInfo.name << "'\n\n" << std::flush;
9345 }
9346 double dur = _sectionStats.durationInSeconds;
9347 if (shouldShowDuration(*m_config, dur)) {
9348 m_stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << '\n' << std::flush;
9349 }
9350 if (m_headerPrinted) {
9351 m_headerPrinted = false;
9352 }
9353 StreamingReporterBase::sectionEnded(_sectionStats);
9354}
9355
9356void ConsoleReporter::benchmarkPreparing( StringRef name ) {
9357 lazyPrintWithoutClosingBenchmarkTable();
9358
9359 auto nameCol = TextFlow::Column( static_cast<std::string>( name ) )
9360 .width( m_tablePrinter->columnInfos()[0].width - 2 );
9361
9362 bool firstLine = true;
9363 for (auto line : nameCol) {
9364 if (!firstLine)
9365 (*m_tablePrinter) << ColumnBreak() << ColumnBreak() << ColumnBreak();
9366 else
9367 firstLine = false;
9368
9369 (*m_tablePrinter) << line << ColumnBreak();
9370 }
9371}
9372
9373void ConsoleReporter::benchmarkStarting(BenchmarkInfo const& info) {
9374 (*m_tablePrinter) << info.samples << ColumnBreak()
9375 << info.iterations << ColumnBreak();
9376 if ( !m_config->benchmarkNoAnalysis() ) {
9377 ( *m_tablePrinter )
9378 << Duration( info.estimatedDuration ) << ColumnBreak();
9379 }
9380 ( *m_tablePrinter ) << OutputFlush{};
9381}
9382void ConsoleReporter::benchmarkEnded(BenchmarkStats<> const& stats) {
9383 if (m_config->benchmarkNoAnalysis())
9384 {
9385 (*m_tablePrinter) << Duration(stats.mean.point.count()) << ColumnBreak();
9386 }
9387 else
9388 {
9389 (*m_tablePrinter) << ColumnBreak()
9390 << Duration(stats.mean.point.count()) << ColumnBreak()
9391 << Duration(stats.mean.lower_bound.count()) << ColumnBreak()
9392 << Duration(stats.mean.upper_bound.count()) << ColumnBreak() << ColumnBreak()
9393 << Duration(stats.standardDeviation.point.count()) << ColumnBreak()
9394 << Duration(stats.standardDeviation.lower_bound.count()) << ColumnBreak()
9395 << Duration(stats.standardDeviation.upper_bound.count()) << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak() << ColumnBreak();
9396 }
9397}
9398
9399void ConsoleReporter::benchmarkFailed( StringRef error ) {
9400 auto guard = m_colour->guardColour( Colour::Red ).engage( m_stream );
9401 (*m_tablePrinter)
9402 << "Benchmark failed (" << error << ')'
9403 << ColumnBreak() << RowBreak();
9404}
9405
9406void ConsoleReporter::testCaseEnded(TestCaseStats const& _testCaseStats) {
9407 m_tablePrinter->close();
9408 StreamingReporterBase::testCaseEnded(_testCaseStats);
9409 m_headerPrinted = false;
9410}
9411void ConsoleReporter::testRunEnded(TestRunStats const& _testRunStats) {
9412 printTotalsDivider(_testRunStats.totals);
9413 printTestRunTotals( m_stream, *m_colour, _testRunStats.totals );
9414 m_stream << '\n' << std::flush;
9415 StreamingReporterBase::testRunEnded(_testRunStats);
9416}
9417void ConsoleReporter::testRunStarting(TestRunInfo const& _testRunInfo) {
9418 StreamingReporterBase::testRunStarting(_testRunInfo);
9419 if ( m_config->testSpec().hasFilters() ) {
9420 m_stream << m_colour->guardColour( Colour::BrightYellow ) << "Filters: "
9421 << m_config->testSpec() << '\n';
9422 }
9423 m_stream << "Randomness seeded to: " << getSeed() << '\n';
9424}
9425
9426void ConsoleReporter::lazyPrint() {
9427
9428 m_tablePrinter->close();
9429 lazyPrintWithoutClosingBenchmarkTable();
9430}
9431
9432void ConsoleReporter::lazyPrintWithoutClosingBenchmarkTable() {
9433
9434 if ( !m_testRunInfoPrinted ) {
9435 lazyPrintRunInfo();
9436 }
9437 if (!m_headerPrinted) {
9438 printTestCaseAndSectionHeader();
9439 m_headerPrinted = true;
9440 }
9441}
9442void ConsoleReporter::lazyPrintRunInfo() {
9443 m_stream << '\n'
9444 << lineOfChars( '~' ) << '\n'
9445 << m_colour->guardColour( Colour::SecondaryText )
9446 << currentTestRunInfo.name << " is a Catch2 v" << libraryVersion()
9447 << " host application.\n"
9448 << "Run with -? for options\n\n";
9449
9450 m_testRunInfoPrinted = true;
9451}
9452void ConsoleReporter::printTestCaseAndSectionHeader() {
9453 assert(!m_sectionStack.empty());
9454 printOpenHeader(currentTestCaseInfo->name);
9455
9456 if (m_sectionStack.size() > 1) {
9457 auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9458
9459 auto
9460 it = m_sectionStack.begin() + 1, // Skip first section (test case)
9461 itEnd = m_sectionStack.end();
9462 for (; it != itEnd; ++it)
9463 printHeaderString(it->name, 2);
9464 }
9465
9466 SourceLineInfo lineInfo = m_sectionStack.back().lineInfo;
9467
9468
9469 m_stream << lineOfChars( '-' ) << '\n'
9470 << m_colour->guardColour( Colour::FileName ) << lineInfo << '\n'
9471 << lineOfChars( '.' ) << "\n\n"
9472 << std::flush;
9473}
9474
9475void ConsoleReporter::printClosedHeader(std::string const& _name) {
9476 printOpenHeader(_name);
9477 m_stream << lineOfChars('.') << '\n';
9478}
9479void ConsoleReporter::printOpenHeader(std::string const& _name) {
9480 m_stream << lineOfChars('-') << '\n';
9481 {
9482 auto guard = m_colour->guardColour( Colour::Headers ).engage( m_stream );
9483 printHeaderString(_name);
9484 }
9485}
9486
9487void ConsoleReporter::printHeaderString(std::string const& _string, std::size_t indent) {
9488 // We want to get a bit fancy with line breaking here, so that subsequent
9489 // lines start after ":" if one is present, e.g.
9490 // ```
9491 // blablabla: Fancy
9492 // linebreaking
9493 // ```
9494 // but we also want to avoid problems with overly long indentation causing
9495 // the text to take up too many lines, e.g.
9496 // ```
9497 // blablabla: F
9498 // a
9499 // n
9500 // c
9501 // y
9502 // .
9503 // .
9504 // .
9505 // ```
9506 // So we limit the prefix indentation check to first quarter of the possible
9507 // width
9508 std::size_t idx = _string.find( ": " );
9509 if ( idx != std::string::npos && idx < CATCH_CONFIG_CONSOLE_WIDTH / 4 ) {
9510 idx += 2;
9511 } else {
9512 idx = 0;
9513 }
9514 m_stream << TextFlow::Column( _string )
9515 .indent( indent + idx )
9516 .initialIndent( indent )
9517 << '\n';
9518}
9519
9520void ConsoleReporter::printTotalsDivider(Totals const& totals) {
9521 if (totals.testCases.total() > 0) {
9522 std::size_t failedRatio = makeRatio(totals.testCases.failed, totals.testCases.total());
9523 std::size_t failedButOkRatio = makeRatio(totals.testCases.failedButOk, totals.testCases.total());
9524 std::size_t passedRatio = makeRatio(totals.testCases.passed, totals.testCases.total());
9525 std::size_t skippedRatio = makeRatio(totals.testCases.skipped, totals.testCases.total());
9526 while (failedRatio + failedButOkRatio + passedRatio + skippedRatio < CATCH_CONFIG_CONSOLE_WIDTH - 1)
9527 findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)++;
9528 while (failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH - 1)
9529 findMax(failedRatio, failedButOkRatio, passedRatio, skippedRatio)--;
9530
9531 m_stream << m_colour->guardColour( Colour::Error )
9532 << std::string( failedRatio, '=' )
9533 << m_colour->guardColour( Colour::ResultExpectedFailure )
9534 << std::string( failedButOkRatio, '=' );
9535 if ( totals.testCases.allPassed() ) {
9536 m_stream << m_colour->guardColour( Colour::ResultSuccess )
9537 << std::string( passedRatio, '=' );
9538 } else {
9539 m_stream << m_colour->guardColour( Colour::Success )
9540 << std::string( passedRatio, '=' );
9541 }
9542 m_stream << m_colour->guardColour( Colour::Skip )
9543 << std::string( skippedRatio, '=' );
9544 } else {
9545 m_stream << m_colour->guardColour( Colour::Warning )
9546 << std::string( CATCH_CONFIG_CONSOLE_WIDTH - 1, '=' );
9547 }
9548 m_stream << '\n';
9549}
9550
9551} // end namespace Catch
9552
9553#if defined(_MSC_VER)
9554#pragma warning(pop)
9555#endif
9556
9557#if defined(__clang__)
9558# pragma clang diagnostic pop
9559#endif
9560
9561
9562
9563
9564#include <algorithm>
9565#include <cassert>
9566
9567namespace Catch {
9568 namespace {
9569 struct BySectionInfo {
9570 BySectionInfo( SectionInfo const& other ): m_other( other ) {}
9571 BySectionInfo( BySectionInfo const& other ) = default;
9572 bool operator()(
9573 Detail::unique_ptr<CumulativeReporterBase::SectionNode> const&
9574 node ) const {
9575 return (
9576 ( node->stats.sectionInfo.name == m_other.name ) &&
9577 ( node->stats.sectionInfo.lineInfo == m_other.lineInfo ) );
9578 }
9579 void operator=( BySectionInfo const& ) = delete;
9580
9581 private:
9582 SectionInfo const& m_other;
9583 };
9584
9585 } // namespace
9586
9587 namespace Detail {
9588 AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9589 AssertionStats const& assertion ):
9590 m_assertion( assertion ) {}
9591
9592 AssertionOrBenchmarkResult::AssertionOrBenchmarkResult(
9593 BenchmarkStats<> const& benchmark ):
9594 m_benchmark( benchmark ) {}
9595
9596 bool AssertionOrBenchmarkResult::isAssertion() const {
9597 return m_assertion.some();
9598 }
9599 bool AssertionOrBenchmarkResult::isBenchmark() const {
9600 return m_benchmark.some();
9601 }
9602
9603 AssertionStats const& AssertionOrBenchmarkResult::asAssertion() const {
9604 assert(m_assertion.some());
9605
9606 return *m_assertion;
9607 }
9608 BenchmarkStats<> const& AssertionOrBenchmarkResult::asBenchmark() const {
9609 assert(m_benchmark.some());
9610
9611 return *m_benchmark;
9612 }
9613
9614 }
9615
9616 CumulativeReporterBase::~CumulativeReporterBase() = default;
9617
9618 void CumulativeReporterBase::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
9619 m_sectionStack.back()->assertionsAndBenchmarks.emplace_back(benchmarkStats);
9620 }
9621
9622 void
9623 CumulativeReporterBase::sectionStarting( SectionInfo const& sectionInfo ) {
9624 // We need a copy, because SectionStats expect to take ownership
9625 SectionStats incompleteStats( SectionInfo(sectionInfo), Counts(), 0, false );
9626 SectionNode* node;
9627 if ( m_sectionStack.empty() ) {
9628 if ( !m_rootSection ) {
9629 m_rootSection =
9630 Detail::make_unique<SectionNode>( incompleteStats );
9631 }
9632 node = m_rootSection.get();
9633 } else {
9634 SectionNode& parentNode = *m_sectionStack.back();
9635 auto it = std::find_if( parentNode.childSections.begin(),
9636 parentNode.childSections.end(),
9637 BySectionInfo( sectionInfo ) );
9638 if ( it == parentNode.childSections.end() ) {
9639 auto newNode =
9640 Detail::make_unique<SectionNode>( incompleteStats );
9641 node = newNode.get();
9642 parentNode.childSections.push_back( CATCH_MOVE( newNode ) );
9643 } else {
9644 node = it->get();
9645 }
9646 }
9647
9648 m_deepestSection = node;
9649 m_sectionStack.push_back( node );
9650 }
9651
9652 void CumulativeReporterBase::assertionEnded(
9653 AssertionStats const& assertionStats ) {
9654 assert( !m_sectionStack.empty() );
9655 // AssertionResult holds a pointer to a temporary DecomposedExpression,
9656 // which getExpandedExpression() calls to build the expression string.
9657 // Our section stack copy of the assertionResult will likely outlive the
9658 // temporary, so it must be expanded or discarded now to avoid calling
9659 // a destroyed object later.
9660 if ( m_shouldStoreFailedAssertions &&
9661 !assertionStats.assertionResult.isOk() ) {
9662 static_cast<void>(
9663 assertionStats.assertionResult.getExpandedExpression() );
9664 }
9665 if ( m_shouldStoreSuccesfulAssertions &&
9666 assertionStats.assertionResult.isOk() ) {
9667 static_cast<void>(
9668 assertionStats.assertionResult.getExpandedExpression() );
9669 }
9670 SectionNode& sectionNode = *m_sectionStack.back();
9671 sectionNode.assertionsAndBenchmarks.emplace_back( assertionStats );
9672 }
9673
9674 void CumulativeReporterBase::sectionEnded( SectionStats const& sectionStats ) {
9675 assert( !m_sectionStack.empty() );
9676 SectionNode& node = *m_sectionStack.back();
9677 node.stats = sectionStats;
9678 m_sectionStack.pop_back();
9679 }
9680
9681 void CumulativeReporterBase::testCaseEnded(
9682 TestCaseStats const& testCaseStats ) {
9683 auto node = Detail::make_unique<TestCaseNode>( testCaseStats );
9684 assert( m_sectionStack.size() == 0 );
9685 node->children.push_back( CATCH_MOVE(m_rootSection) );
9686 m_testCases.push_back( CATCH_MOVE(node) );
9687
9688 assert( m_deepestSection );
9689 m_deepestSection->stdOut = testCaseStats.stdOut;
9690 m_deepestSection->stdErr = testCaseStats.stdErr;
9691 }
9692
9693
9694 void CumulativeReporterBase::testRunEnded( TestRunStats const& testRunStats ) {
9695 assert(!m_testRun && "CumulativeReporterBase assumes there can only be one test run");
9696 m_testRun = Detail::make_unique<TestRunNode>( testRunStats );
9697 m_testRun->children.swap( m_testCases );
9698 testRunEndedCumulative();
9699 }
9700
9701 bool CumulativeReporterBase::SectionNode::hasAnyAssertions() const {
9702 return std::any_of(
9703 assertionsAndBenchmarks.begin(),
9704 assertionsAndBenchmarks.end(),
9705 []( Detail::AssertionOrBenchmarkResult const& res ) {
9706 return res.isAssertion();
9707 } );
9708 }
9709
9710} // end namespace Catch
9711
9712
9713
9714
9715namespace Catch {
9716
9717 void EventListenerBase::fatalErrorEncountered( StringRef ) {}
9718
9719 void EventListenerBase::benchmarkPreparing( StringRef ) {}
9720 void EventListenerBase::benchmarkStarting( BenchmarkInfo const& ) {}
9721 void EventListenerBase::benchmarkEnded( BenchmarkStats<> const& ) {}
9722 void EventListenerBase::benchmarkFailed( StringRef ) {}
9723
9724 void EventListenerBase::assertionStarting( AssertionInfo const& ) {}
9725
9726 void EventListenerBase::assertionEnded( AssertionStats const& ) {}
9727 void EventListenerBase::listReporters(
9728 std::vector<ReporterDescription> const& ) {}
9729 void EventListenerBase::listListeners(
9730 std::vector<ListenerDescription> const& ) {}
9731 void EventListenerBase::listTests( std::vector<TestCaseHandle> const& ) {}
9732 void EventListenerBase::listTags( std::vector<TagInfo> const& ) {}
9733 void EventListenerBase::noMatchingTestCases( StringRef ) {}
9734 void EventListenerBase::reportInvalidTestSpec( StringRef ) {}
9735 void EventListenerBase::testRunStarting( TestRunInfo const& ) {}
9736 void EventListenerBase::testCaseStarting( TestCaseInfo const& ) {}
9737 void EventListenerBase::testCasePartialStarting(TestCaseInfo const&, uint64_t) {}
9738 void EventListenerBase::sectionStarting( SectionInfo const& ) {}
9739 void EventListenerBase::sectionEnded( SectionStats const& ) {}
9740 void EventListenerBase::testCasePartialEnded(TestCaseStats const&, uint64_t) {}
9741 void EventListenerBase::testCaseEnded( TestCaseStats const& ) {}
9742 void EventListenerBase::testRunEnded( TestRunStats const& ) {}
9743 void EventListenerBase::skipTest( TestCaseInfo const& ) {}
9744} // namespace Catch
9745
9746
9747
9748
9749#include <algorithm>
9750#include <cfloat>
9751#include <cstdio>
9752#include <ostream>
9753#include <iomanip>
9754
9755namespace Catch {
9756
9757 namespace {
9758 void listTestNamesOnly(std::ostream& out,
9759 std::vector<TestCaseHandle> const& tests) {
9760 for (auto const& test : tests) {
9761 auto const& testCaseInfo = test.getTestCaseInfo();
9762
9763 if (startsWith(testCaseInfo.name, '#')) {
9764 out << '"' << testCaseInfo.name << '"';
9765 } else {
9766 out << testCaseInfo.name;
9767 }
9768
9769 out << '\n';
9770 }
9771 out << std::flush;
9772 }
9773 } // end unnamed namespace
9774
9775
9776 // Because formatting using c++ streams is stateful, drop down to C is
9777 // required Alternatively we could use stringstream, but its performance
9778 // is... not good.
9779 std::string getFormattedDuration( double duration ) {
9780 // Max exponent + 1 is required to represent the whole part
9781 // + 1 for decimal point
9782 // + 3 for the 3 decimal places
9783 // + 1 for null terminator
9784 const std::size_t maxDoubleSize = DBL_MAX_10_EXP + 1 + 1 + 3 + 1;
9785 char buffer[maxDoubleSize];
9786
9787 // Save previous errno, to prevent sprintf from overwriting it
9788 ErrnoGuard guard;
9789#ifdef _MSC_VER
9790 size_t printedLength = static_cast<size_t>(
9791 sprintf_s( buffer, "%.3f", duration ) );
9792#else
9793 size_t printedLength = static_cast<size_t>(
9794 std::snprintf( buffer, maxDoubleSize, "%.3f", duration ) );
9795#endif
9796 return std::string( buffer, printedLength );
9797 }
9798
9799 bool shouldShowDuration( IConfig const& config, double duration ) {
9800 if ( config.showDurations() == ShowDurations::Always ) {
9801 return true;
9802 }
9803 if ( config.showDurations() == ShowDurations::Never ) {
9804 return false;
9805 }
9806 const double min = config.minDuration();
9807 return min >= 0 && duration >= min;
9808 }
9809
9810 std::string serializeFilters( std::vector<std::string> const& filters ) {
9811 // We add a ' ' separator between each filter
9812 size_t serialized_size = filters.size() - 1;
9813 for (auto const& filter : filters) {
9814 serialized_size += filter.size();
9815 }
9816
9817 std::string serialized;
9818 serialized.reserve(serialized_size);
9819 bool first = true;
9820
9821 for (auto const& filter : filters) {
9822 if (!first) {
9823 serialized.push_back(' ');
9824 }
9825 first = false;
9826 serialized.append(filter);
9827 }
9828
9829 return serialized;
9830 }
9831
9832 std::ostream& operator<<( std::ostream& out, lineOfChars value ) {
9833 for ( size_t idx = 0; idx < CATCH_CONFIG_CONSOLE_WIDTH - 1; ++idx ) {
9834 out.put( value.c );
9835 }
9836 return out;
9837 }
9838
9839 void
9840 defaultListReporters( std::ostream& out,
9841 std::vector<ReporterDescription> const& descriptions,
9842 Verbosity verbosity ) {
9843 out << "Available reporters:\n";
9844 const auto maxNameLen =
9845 std::max_element( descriptions.begin(),
9846 descriptions.end(),
9847 []( ReporterDescription const& lhs,
9848 ReporterDescription const& rhs ) {
9849 return lhs.name.size() < rhs.name.size();
9850 } )
9851 ->name.size();
9852
9853 for ( auto const& desc : descriptions ) {
9854 if ( verbosity == Verbosity::Quiet ) {
9855 out << TextFlow::Column( desc.name )
9856 .indent( 2 )
9857 .width( 5 + maxNameLen )
9858 << '\n';
9859 } else {
9860 out << TextFlow::Column( desc.name + ':' )
9861 .indent( 2 )
9862 .width( 5 + maxNameLen ) +
9863 TextFlow::Column( desc.description )
9864 .initialIndent( 0 )
9865 .indent( 2 )
9866 .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
9867 << '\n';
9868 }
9869 }
9870 out << '\n' << std::flush;
9871 }
9872
9873 void defaultListListeners( std::ostream& out,
9874 std::vector<ListenerDescription> const& descriptions ) {
9875 out << "Registered listeners:\n";
9876
9877 if(descriptions.empty()) {
9878 return;
9879 }
9880
9881 const auto maxNameLen =
9882 std::max_element( descriptions.begin(),
9883 descriptions.end(),
9884 []( ListenerDescription const& lhs,
9885 ListenerDescription const& rhs ) {
9886 return lhs.name.size() < rhs.name.size();
9887 } )
9888 ->name.size();
9889
9890 for ( auto const& desc : descriptions ) {
9891 out << TextFlow::Column( static_cast<std::string>( desc.name ) +
9892 ':' )
9893 .indent( 2 )
9894 .width( maxNameLen + 5 ) +
9895 TextFlow::Column( desc.description )
9896 .initialIndent( 0 )
9897 .indent( 2 )
9898 .width( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen - 8 )
9899 << '\n';
9900 }
9901
9902 out << '\n' << std::flush;
9903 }
9904
9905 void defaultListTags( std::ostream& out,
9906 std::vector<TagInfo> const& tags,
9907 bool isFiltered ) {
9908 if ( isFiltered ) {
9909 out << "Tags for matching test cases:\n";
9910 } else {
9911 out << "All available tags:\n";
9912 }
9913
9914 for ( auto const& tagCount : tags ) {
9915 ReusableStringStream rss;
9916 rss << " " << std::setw( 2 ) << tagCount.count << " ";
9917 auto str = rss.str();
9918 auto wrapper = TextFlow::Column( tagCount.all() )
9919 .initialIndent( 0 )
9920 .indent( str.size() )
9921 .width( CATCH_CONFIG_CONSOLE_WIDTH - 10 );
9922 out << str << wrapper << '\n';
9923 }
9924 out << pluralise(tags.size(), "tag"_sr) << "\n\n" << std::flush;
9925 }
9926
9927 void defaultListTests(std::ostream& out, ColourImpl* streamColour, std::vector<TestCaseHandle> const& tests, bool isFiltered, Verbosity verbosity) {
9928 // We special case this to provide the equivalent of old
9929 // `--list-test-names-only`, which could then be used by the
9930 // `--input-file` option.
9931 if (verbosity == Verbosity::Quiet) {
9932 listTestNamesOnly(out, tests);
9933 return;
9934 }
9935
9936 if (isFiltered) {
9937 out << "Matching test cases:\n";
9938 } else {
9939 out << "All available test cases:\n";
9940 }
9941
9942 for (auto const& test : tests) {
9943 auto const& testCaseInfo = test.getTestCaseInfo();
9944 Colour::Code colour = testCaseInfo.isHidden()
9945 ? Colour::SecondaryText
9946 : Colour::None;
9947 auto colourGuard = streamColour->guardColour( colour ).engage( out );
9948
9949 out << TextFlow::Column(testCaseInfo.name).indent(2) << '\n';
9950 if (verbosity >= Verbosity::High) {
9951 out << TextFlow::Column(Catch::Detail::stringify(testCaseInfo.lineInfo)).indent(4) << '\n';
9952 }
9953 if (!testCaseInfo.tags.empty() &&
9954 verbosity > Verbosity::Quiet) {
9955 out << TextFlow::Column(testCaseInfo.tagsAsString()).indent(6) << '\n';
9956 }
9957 }
9958
9959 if (isFiltered) {
9960 out << pluralise(tests.size(), "matching test case"_sr);
9961 } else {
9962 out << pluralise(tests.size(), "test case"_sr);
9963 }
9964 out << "\n\n" << std::flush;
9965 }
9966
9967 namespace {
9968 class SummaryColumn {
9969 public:
9970 SummaryColumn( std::string suffix, Colour::Code colour ):
9971 m_suffix( CATCH_MOVE( suffix ) ), m_colour( colour ) {}
9972
9973 SummaryColumn&& addRow( std::uint64_t count ) && {
9974 std::string row = std::to_string(count);
9975 auto const new_width = std::max( m_width, row.size() );
9976 if ( new_width > m_width ) {
9977 for ( auto& oldRow : m_rows ) {
9978 oldRow.insert( 0, new_width - m_width, ' ' );
9979 }
9980 } else {
9981 row.insert( 0, m_width - row.size(), ' ' );
9982 }
9983 m_width = new_width;
9984 m_rows.push_back( row );
9985 return std::move( *this );
9986 }
9987
9988 std::string const& getSuffix() const { return m_suffix; }
9989 Colour::Code getColour() const { return m_colour; }
9990 std::string const& getRow( std::size_t index ) const {
9991 return m_rows[index];
9992 }
9993
9994 private:
9995 std::string m_suffix;
9996 Colour::Code m_colour;
9997 std::size_t m_width = 0;
9998 std::vector<std::string> m_rows;
9999 };
10000
10001 void printSummaryRow( std::ostream& stream,
10002 ColourImpl& colour,
10003 StringRef label,
10004 std::vector<SummaryColumn> const& cols,
10005 std::size_t row ) {
10006 for ( auto const& col : cols ) {
10007 auto const& value = col.getRow( row );
10008 auto const& suffix = col.getSuffix();
10009 if ( suffix.empty() ) {
10010 stream << label << ": ";
10011 if ( value != "0" ) {
10012 stream << value;
10013 } else {
10014 stream << colour.guardColour( Colour::Warning )
10015 << "- none -";
10016 }
10017 } else if ( value != "0" ) {
10018 stream << colour.guardColour( Colour::LightGrey ) << " | "
10019 << colour.guardColour( col.getColour() ) << value
10020 << ' ' << suffix;
10021 }
10022 }
10023 stream << '\n';
10024 }
10025 } // namespace
10026
10027 void printTestRunTotals( std::ostream& stream,
10028 ColourImpl& streamColour,
10029 Totals const& totals ) {
10030 if ( totals.testCases.total() == 0 ) {
10031 stream << streamColour.guardColour( Colour::Warning )
10032 << "No tests ran\n";
10033 return;
10034 }
10035
10036 if ( totals.assertions.total() > 0 && totals.testCases.allPassed() ) {
10037 stream << streamColour.guardColour( Colour::ResultSuccess )
10038 << "All tests passed";
10039 stream << " ("
10040 << pluralise( totals.assertions.passed, "assertion"_sr )
10041 << " in "
10042 << pluralise( totals.testCases.passed, "test case"_sr )
10043 << ')' << '\n';
10044 return;
10045 }
10046
10047 std::vector<SummaryColumn> columns;
10048 // Don't include "skipped assertions" in total count
10049 const auto totalAssertionCount =
10050 totals.assertions.total() - totals.assertions.skipped;
10051 columns.push_back( SummaryColumn( "", Colour::None )
10052 .addRow( totals.testCases.total() )
10053 .addRow( totalAssertionCount ) );
10054 columns.push_back( SummaryColumn( "passed", Colour::Success )
10055 .addRow( totals.testCases.passed )
10056 .addRow( totals.assertions.passed ) );
10057 columns.push_back( SummaryColumn( "failed", Colour::ResultError )
10058 .addRow( totals.testCases.failed )
10059 .addRow( totals.assertions.failed ) );
10060 columns.push_back( SummaryColumn( "skipped", Colour::Skip )
10061 .addRow( totals.testCases.skipped )
10062 // Don't print "skipped assertions"
10063 .addRow( 0 ) );
10064 columns.push_back(
10065 SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
10066 .addRow( totals.testCases.failedButOk )
10067 .addRow( totals.assertions.failedButOk ) );
10068 printSummaryRow( stream, streamColour, "test cases"_sr, columns, 0 );
10069 printSummaryRow( stream, streamColour, "assertions"_sr, columns, 1 );
10070 }
10071
10072} // namespace Catch
10073
10074
10075//
10076
10077namespace Catch {
10078 namespace {
10079 void writeSourceInfo( JsonObjectWriter& writer,
10080 SourceLineInfo const& sourceInfo ) {
10081 auto source_location_writer =
10082 writer.write( "source-location"_sr ).writeObject();
10083 source_location_writer.write( "filename"_sr )
10084 .write( sourceInfo.file );
10085 source_location_writer.write( "line"_sr ).write( sourceInfo.line );
10086 }
10087
10088 void writeTags( JsonArrayWriter writer, std::vector<Tag> const& tags ) {
10089 for ( auto const& tag : tags ) {
10090 writer.write( tag.original );
10091 }
10092 }
10093
10094 void writeProperties( JsonArrayWriter writer,
10095 TestCaseInfo const& info ) {
10096 if ( info.isHidden() ) { writer.write( "is-hidden"_sr ); }
10097 if ( info.okToFail() ) { writer.write( "ok-to-fail"_sr ); }
10098 if ( info.expectedToFail() ) {
10099 writer.write( "expected-to-fail"_sr );
10100 }
10101 if ( info.throws() ) { writer.write( "throws"_sr ); }
10102 }
10103
10104 } // namespace
10105
10106 JsonReporter::JsonReporter( ReporterConfig&& config ):
10107 StreamingReporterBase{ CATCH_MOVE( config ) } {
10108
10109 m_preferences.shouldRedirectStdOut = true;
10110 // TBD: Do we want to report all assertions? XML reporter does
10111 // not, but for machine-parseable reporters I think the answer
10112 // should be yes.
10113 m_preferences.shouldReportAllAssertions = true;
10114
10115 m_objectWriters.emplace( m_stream );
10116 m_writers.emplace( Writer::Object );
10117 auto& writer = m_objectWriters.top();
10118
10119 writer.write( "version"_sr ).write( 1 );
10120
10121 {
10122 auto metadata_writer = writer.write( "metadata"_sr ).writeObject();
10123 metadata_writer.write( "name"_sr ).write( m_config->name() );
10124 metadata_writer.write( "rng-seed"_sr ).write( m_config->rngSeed() );
10125 metadata_writer.write( "catch2-version"_sr )
10126 .write( libraryVersion() );
10127 if ( m_config->testSpec().hasFilters() ) {
10128 metadata_writer.write( "filters"_sr )
10129 .write( m_config->testSpec() );
10130 }
10131 }
10132 }
10133
10134 JsonReporter::~JsonReporter() {
10135 endListing();
10136 // TODO: Ensure this closes the top level object, add asserts
10137 assert( m_writers.size() == 1 && "Only the top level object should be open" );
10138 assert( m_writers.top() == Writer::Object );
10139 endObject();
10140 m_stream << '\n' << std::flush;
10141 assert( m_writers.empty() );
10142 }
10143
10144 JsonArrayWriter& JsonReporter::startArray() {
10145 m_arrayWriters.emplace( m_arrayWriters.top().writeArray() );
10146 m_writers.emplace( Writer::Array );
10147 return m_arrayWriters.top();
10148 }
10149 JsonArrayWriter& JsonReporter::startArray( StringRef key ) {
10150 m_arrayWriters.emplace(
10151 m_objectWriters.top().write( key ).writeArray() );
10152 m_writers.emplace( Writer::Array );
10153 return m_arrayWriters.top();
10154 }
10155
10156 JsonObjectWriter& JsonReporter::startObject() {
10157 m_objectWriters.emplace( m_arrayWriters.top().writeObject() );
10158 m_writers.emplace( Writer::Object );
10159 return m_objectWriters.top();
10160 }
10161 JsonObjectWriter& JsonReporter::startObject( StringRef key ) {
10162 m_objectWriters.emplace(
10163 m_objectWriters.top().write( key ).writeObject() );
10164 m_writers.emplace( Writer::Object );
10165 return m_objectWriters.top();
10166 }
10167
10168 void JsonReporter::endObject() {
10169 assert( isInside( Writer::Object ) );
10170 m_objectWriters.pop();
10171 m_writers.pop();
10172 }
10173 void JsonReporter::endArray() {
10174 assert( isInside( Writer::Array ) );
10175 m_arrayWriters.pop();
10176 m_writers.pop();
10177 }
10178
10179 bool JsonReporter::isInside( Writer writer ) {
10180 return !m_writers.empty() && m_writers.top() == writer;
10181 }
10182
10183 void JsonReporter::startListing() {
10184 if ( !m_startedListing ) { startObject( "listings"_sr ); }
10185 m_startedListing = true;
10186 }
10187 void JsonReporter::endListing() {
10188 if ( m_startedListing ) { endObject(); }
10189 m_startedListing = false;
10190 }
10191
10192 std::string JsonReporter::getDescription() {
10193 return "Outputs listings as JSON. Test listing is Work-in-Progress!";
10194 }
10195
10196 void JsonReporter::testRunStarting( TestRunInfo const& runInfo ) {
10197 StreamingReporterBase::testRunStarting( runInfo );
10198 endListing();
10199
10200 assert( isInside( Writer::Object ) );
10201 startObject( "test-run"_sr );
10202 startArray( "test-cases"_sr );
10203 }
10204
10205 static void writeCounts( JsonObjectWriter&& writer, Counts const& counts ) {
10206 writer.write( "passed"_sr ).write( counts.passed );
10207 writer.write( "failed"_sr ).write( counts.failed );
10208 writer.write( "fail-but-ok"_sr ).write( counts.failedButOk );
10209 writer.write( "skipped"_sr ).write( counts.skipped );
10210 }
10211
10212 void JsonReporter::testRunEnded(TestRunStats const& runStats) {
10213 assert( isInside( Writer::Array ) );
10214 // End "test-cases"
10215 endArray();
10216
10217 {
10218 auto totals =
10219 m_objectWriters.top().write( "totals"_sr ).writeObject();
10220 writeCounts( totals.write( "assertions"_sr ).writeObject(),
10221 runStats.totals.assertions );
10222 writeCounts( totals.write( "test-cases"_sr ).writeObject(),
10223 runStats.totals.testCases );
10224 }
10225
10226 // End the "test-run" object
10227 endObject();
10228 }
10229
10230 void JsonReporter::testCaseStarting( TestCaseInfo const& tcInfo ) {
10231 StreamingReporterBase::testCaseStarting( tcInfo );
10232
10233 assert( isInside( Writer::Array ) &&
10234 "We should be in the 'test-cases' array" );
10235 startObject();
10236 // "test-info" prelude
10237 {
10238 auto testInfo =
10239 m_objectWriters.top().write( "test-info"_sr ).writeObject();
10240 // TODO: handle testName vs className!!
10241 testInfo.write( "name"_sr ).write( tcInfo.name );
10242 writeSourceInfo(testInfo, tcInfo.lineInfo);
10243 writeTags( testInfo.write( "tags"_sr ).writeArray(), tcInfo.tags );
10244 writeProperties( testInfo.write( "properties"_sr ).writeArray(),
10245 tcInfo );
10246 }
10247
10248
10249 // Start the array for individual test runs (testCasePartial pairs)
10250 startArray( "runs"_sr );
10251 }
10252
10253 void JsonReporter::testCaseEnded( TestCaseStats const& tcStats ) {
10254 StreamingReporterBase::testCaseEnded( tcStats );
10255
10256 // We need to close the 'runs' array before finishing the test case
10257 assert( isInside( Writer::Array ) );
10258 endArray();
10259
10260 {
10261 auto totals =
10262 m_objectWriters.top().write( "totals"_sr ).writeObject();
10263 writeCounts( totals.write( "assertions"_sr ).writeObject(),
10264 tcStats.totals.assertions );
10265 // We do not write the test case totals, because there will always be just one test case here.
10266 // TODO: overall "result" -> success, skip, fail here? Or in partial result?
10267 }
10268 // We do not write out stderr/stdout, because we instead wrote those out in partial runs
10269
10270 // TODO: aborting?
10271
10272 // And we also close this test case's object
10273 assert( isInside( Writer::Object ) );
10274 endObject();
10275 }
10276
10277 void JsonReporter::testCasePartialStarting( TestCaseInfo const& /*tcInfo*/,
10278 uint64_t index ) {
10279 startObject();
10280 m_objectWriters.top().write( "run-idx"_sr ).write( index );
10281 startArray( "path"_sr );
10282 // TODO: we want to delay most of the printing to the 'root' section
10283 // TODO: childSection key name?
10284 }
10285
10286 void JsonReporter::testCasePartialEnded( TestCaseStats const& tcStats,
10287 uint64_t /*index*/ ) {
10288 // Fixme: the top level section handles this.
10289 //// path object
10290 endArray();
10291 if ( !tcStats.stdOut.empty() ) {
10292 m_objectWriters.top()
10293 .write( "captured-stdout"_sr )
10294 .write( tcStats.stdOut );
10295 }
10296 if ( !tcStats.stdErr.empty() ) {
10297 m_objectWriters.top()
10298 .write( "captured-stderr"_sr )
10299 .write( tcStats.stdErr );
10300 }
10301 {
10302 auto totals =
10303 m_objectWriters.top().write( "totals"_sr ).writeObject();
10304 writeCounts( totals.write( "assertions"_sr ).writeObject(),
10305 tcStats.totals.assertions );
10306 // We do not write the test case totals, because there will
10307 // always be just one test case here.
10308 // TODO: overall "result" -> success, skip, fail here? Or in
10309 // partial result?
10310 }
10311 // TODO: aborting?
10312 // run object
10313 endObject();
10314 }
10315
10316 void JsonReporter::sectionStarting( SectionInfo const& sectionInfo ) {
10317 assert( isInside( Writer::Array ) &&
10318 "Section should always start inside an object" );
10319 // We want to nest top level sections, even though it shares name
10320 // and source loc with the TEST_CASE
10321 auto& sectionObject = startObject();
10322 sectionObject.write( "kind"_sr ).write( "section"_sr );
10323 sectionObject.write( "name"_sr ).write( sectionInfo.name );
10324 writeSourceInfo( m_objectWriters.top(), sectionInfo.lineInfo );
10325
10326
10327 // TBD: Do we want to create this event lazily? It would become
10328 // rather complex, but we could do it, and it would look
10329 // better for empty sections. OTOH, empty sections should
10330 // be rare.
10331 startArray( "path"_sr );
10332 }
10333 void JsonReporter::sectionEnded( SectionStats const& /*sectionStats */) {
10334 // End the subpath array
10335 endArray();
10336 // TODO: metadata
10337 // TODO: what info do we have here?
10338
10339 // End the section object
10340 endObject();
10341 }
10342
10343 void JsonReporter::assertionStarting( AssertionInfo const& /*assertionInfo*/ ) {}
10344 void JsonReporter::assertionEnded( AssertionStats const& assertionStats ) {
10345 // TODO: There is lot of different things to handle here, but
10346 // we can fill it in later, after we show that the basic
10347 // outline and streaming reporter impl works well enough.
10348 //if ( !m_config->includeSuccessfulResults()
10349 // && assertionStats.assertionResult.isOk() ) {
10350 // return;
10351 //}
10352 assert( isInside( Writer::Array ) );
10353 auto assertionObject = m_arrayWriters.top().writeObject();
10354
10355 assertionObject.write( "kind"_sr ).write( "assertion"_sr );
10356 writeSourceInfo( assertionObject,
10357 assertionStats.assertionResult.getSourceInfo() );
10358 assertionObject.write( "status"_sr )
10359 .write( assertionStats.assertionResult.isOk() );
10360 // TODO: handling of result.
10361 // TODO: messages
10362 // TODO: totals?
10363 }
10364
10365
10366 void JsonReporter::benchmarkPreparing( StringRef name ) { (void)name; }
10367 void JsonReporter::benchmarkStarting( BenchmarkInfo const& ) {}
10368 void JsonReporter::benchmarkEnded( BenchmarkStats<> const& ) {}
10369 void JsonReporter::benchmarkFailed( StringRef error ) { (void)error; }
10370
10371 void JsonReporter::listReporters(
10372 std::vector<ReporterDescription> const& descriptions ) {
10373 startListing();
10374
10375 auto writer =
10376 m_objectWriters.top().write( "reporters"_sr ).writeArray();
10377 for ( auto const& desc : descriptions ) {
10378 auto desc_writer = writer.writeObject();
10379 desc_writer.write( "name"_sr ).write( desc.name );
10380 desc_writer.write( "description"_sr ).write( desc.description );
10381 }
10382 }
10383 void JsonReporter::listListeners(
10384 std::vector<ListenerDescription> const& descriptions ) {
10385 startListing();
10386
10387 auto writer =
10388 m_objectWriters.top().write( "listeners"_sr ).writeArray();
10389
10390 for ( auto const& desc : descriptions ) {
10391 auto desc_writer = writer.writeObject();
10392 desc_writer.write( "name"_sr ).write( desc.name );
10393 desc_writer.write( "description"_sr ).write( desc.description );
10394 }
10395 }
10396 void JsonReporter::listTests( std::vector<TestCaseHandle> const& tests ) {
10397 startListing();
10398
10399 auto writer = m_objectWriters.top().write( "tests"_sr ).writeArray();
10400
10401 for ( auto const& test : tests ) {
10402 auto desc_writer = writer.writeObject();
10403 auto const& info = test.getTestCaseInfo();
10404
10405 desc_writer.write( "name"_sr ).write( info.name );
10406 desc_writer.write( "class-name"_sr ).write( info.className );
10407 {
10408 auto tag_writer = desc_writer.write( "tags"_sr ).writeArray();
10409 for ( auto const& tag : info.tags ) {
10410 tag_writer.write( tag.original );
10411 }
10412 }
10413 writeSourceInfo( desc_writer, info.lineInfo );
10414 }
10415 }
10416 void JsonReporter::listTags( std::vector<TagInfo> const& tags ) {
10417 startListing();
10418
10419 auto writer = m_objectWriters.top().write( "tags"_sr ).writeArray();
10420 for ( auto const& tag : tags ) {
10421 auto tag_writer = writer.writeObject();
10422 {
10423 auto aliases_writer =
10424 tag_writer.write( "aliases"_sr ).writeArray();
10425 for ( auto alias : tag.spellings ) {
10426 aliases_writer.write( alias );
10427 }
10428 }
10429 tag_writer.write( "count"_sr ).write( tag.count );
10430 }
10431 }
10432} // namespace Catch
10433
10434
10435
10436
10437#include <cassert>
10438#include <ctime>
10439#include <algorithm>
10440#include <iomanip>
10441
10442namespace Catch {
10443
10444 namespace {
10445 std::string getCurrentTimestamp() {
10446 time_t rawtime;
10447 std::time(&rawtime);
10448
10449 std::tm timeInfo = {};
10450#if defined (_MSC_VER) || defined (__MINGW32__)
10451 gmtime_s(&timeInfo, &rawtime);
10452#elif defined (CATCH_PLATFORM_PLAYSTATION)
10453 gmtime_s(&rawtime, &timeInfo);
10454#elif defined (__IAR_SYSTEMS_ICC__)
10455 timeInfo = *std::gmtime(&rawtime);
10456#else
10457 gmtime_r(&rawtime, &timeInfo);
10458#endif
10459
10460 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
10461 char timeStamp[timeStampSize];
10462 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
10463
10464 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
10465
10466 return std::string(timeStamp, timeStampSize - 1);
10467 }
10468
10469 std::string fileNameTag(std::vector<Tag> const& tags) {
10470 auto it = std::find_if(begin(tags),
10471 end(tags),
10472 [] (Tag const& tag) {
10473 return tag.original.size() > 0
10474 && tag.original[0] == '#'; });
10475 if (it != tags.end()) {
10476 return static_cast<std::string>(
10477 it->original.substr(1, it->original.size() - 1)
10478 );
10479 }
10480 return std::string();
10481 }
10482
10483 // Formats the duration in seconds to 3 decimal places.
10484 // This is done because some genius defined Maven Surefire schema
10485 // in a way that only accepts 3 decimal places, and tools like
10486 // Jenkins use that schema for validation JUnit reporter output.
10487 std::string formatDuration( double seconds ) {
10488 ReusableStringStream rss;
10489 rss << std::fixed << std::setprecision( 3 ) << seconds;
10490 return rss.str();
10491 }
10492
10493 static void normalizeNamespaceMarkers(std::string& str) {
10494 std::size_t pos = str.find( "::" );
10495 while ( pos != std::string::npos ) {
10496 str.replace( pos, 2, "." );
10497 pos += 1;
10498 pos = str.find( "::", pos );
10499 }
10500 }
10501
10502 } // anonymous namespace
10503
10504 JunitReporter::JunitReporter( ReporterConfig&& _config )
10505 : CumulativeReporterBase( CATCH_MOVE(_config) ),
10506 xml( m_stream )
10507 {
10508 m_preferences.shouldRedirectStdOut = true;
10509 m_preferences.shouldReportAllAssertions = false;
10510 m_shouldStoreSuccesfulAssertions = false;
10511 }
10512
10513 std::string JunitReporter::getDescription() {
10514 return "Reports test results in an XML format that looks like Ant's junitreport target";
10515 }
10516
10517 void JunitReporter::testRunStarting( TestRunInfo const& runInfo ) {
10518 CumulativeReporterBase::testRunStarting( runInfo );
10519 xml.startElement( "testsuites" );
10520 suiteTimer.start();
10521 stdOutForSuite.clear();
10522 stdErrForSuite.clear();
10523 unexpectedExceptions = 0;
10524 }
10525
10526 void JunitReporter::testCaseStarting( TestCaseInfo const& testCaseInfo ) {
10527 m_okToFail = testCaseInfo.okToFail();
10528 }
10529
10530 void JunitReporter::assertionEnded( AssertionStats const& assertionStats ) {
10531 if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException && !m_okToFail )
10532 unexpectedExceptions++;
10533 CumulativeReporterBase::assertionEnded( assertionStats );
10534 }
10535
10536 void JunitReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
10537 stdOutForSuite += testCaseStats.stdOut;
10538 stdErrForSuite += testCaseStats.stdErr;
10539 CumulativeReporterBase::testCaseEnded( testCaseStats );
10540 }
10541
10542 void JunitReporter::testRunEndedCumulative() {
10543 const auto suiteTime = suiteTimer.getElapsedSeconds();
10544 writeRun( *m_testRun, suiteTime );
10545 xml.endElement();
10546 }
10547
10548 void JunitReporter::writeRun( TestRunNode const& testRunNode, double suiteTime ) {
10549 XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
10550
10551 TestRunStats const& stats = testRunNode.value;
10552 xml.writeAttribute( "name"_sr, stats.runInfo.name );
10553 xml.writeAttribute( "errors"_sr, unexpectedExceptions );
10554 xml.writeAttribute( "failures"_sr, stats.totals.assertions.failed-unexpectedExceptions );
10555 xml.writeAttribute( "skipped"_sr, stats.totals.assertions.skipped );
10556 xml.writeAttribute( "tests"_sr, stats.totals.assertions.total() );
10557 xml.writeAttribute( "hostname"_sr, "tbd"_sr ); // !TBD
10558 if( m_config->showDurations() == ShowDurations::Never )
10559 xml.writeAttribute( "time"_sr, ""_sr );
10560 else
10561 xml.writeAttribute( "time"_sr, formatDuration( suiteTime ) );
10562 xml.writeAttribute( "timestamp"_sr, getCurrentTimestamp() );
10563
10564 // Write properties
10565 {
10566 auto properties = xml.scopedElement("properties");
10567 xml.scopedElement("property")
10568 .writeAttribute("name"_sr, "random-seed"_sr)
10569 .writeAttribute("value"_sr, m_config->rngSeed());
10570 if (m_config->testSpec().hasFilters()) {
10571 xml.scopedElement("property")
10572 .writeAttribute("name"_sr, "filters"_sr)
10573 .writeAttribute("value"_sr, m_config->testSpec());
10574 }
10575 }
10576
10577 // Write test cases
10578 for( auto const& child : testRunNode.children )
10579 writeTestCase( *child );
10580
10581 xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite ), XmlFormatting::Newline );
10582 xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite ), XmlFormatting::Newline );
10583 }
10584
10585 void JunitReporter::writeTestCase( TestCaseNode const& testCaseNode ) {
10586 TestCaseStats const& stats = testCaseNode.value;
10587
10588 // All test cases have exactly one section - which represents the
10589 // test case itself. That section may have 0-n nested sections
10590 assert( testCaseNode.children.size() == 1 );
10591 SectionNode const& rootSection = *testCaseNode.children.front();
10592
10593 std::string className =
10594 static_cast<std::string>( stats.testInfo->className );
10595
10596 if( className.empty() ) {
10597 className = fileNameTag(stats.testInfo->tags);
10598 if ( className.empty() ) {
10599 className = "global";
10600 }
10601 }
10602
10603 if ( !m_config->name().empty() )
10604 className = static_cast<std::string>(m_config->name()) + '.' + className;
10605
10606 normalizeNamespaceMarkers(className);
10607
10608 writeSection( className, "", rootSection, stats.testInfo->okToFail() );
10609 }
10610
10611 void JunitReporter::writeSection( std::string const& className,
10612 std::string const& rootName,
10613 SectionNode const& sectionNode,
10614 bool testOkToFail) {
10615 std::string name = trim( sectionNode.stats.sectionInfo.name );
10616 if( !rootName.empty() )
10617 name = rootName + '/' + name;
10618
10619 if ( sectionNode.stats.assertions.total() > 0
10620 || !sectionNode.stdOut.empty()
10621 || !sectionNode.stdErr.empty() ) {
10622 XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
10623 if( className.empty() ) {
10624 xml.writeAttribute( "classname"_sr, name );
10625 xml.writeAttribute( "name"_sr, "root"_sr );
10626 }
10627 else {
10628 xml.writeAttribute( "classname"_sr, className );
10629 xml.writeAttribute( "name"_sr, name );
10630 }
10631 xml.writeAttribute( "time"_sr, formatDuration( sectionNode.stats.durationInSeconds ) );
10632 // This is not ideal, but it should be enough to mimic gtest's
10633 // junit output.
10634 // Ideally the JUnit reporter would also handle `skipTest`
10635 // events and write those out appropriately.
10636 xml.writeAttribute( "status"_sr, "run"_sr );
10637
10638 if (sectionNode.stats.assertions.failedButOk) {
10639 xml.scopedElement("skipped")
10640 .writeAttribute("message", "TEST_CASE tagged with !mayfail");
10641 }
10642
10643 writeAssertions( sectionNode );
10644
10645
10646 if( !sectionNode.stdOut.empty() )
10647 xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), XmlFormatting::Newline );
10648 if( !sectionNode.stdErr.empty() )
10649 xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), XmlFormatting::Newline );
10650 }
10651 for( auto const& childNode : sectionNode.childSections )
10652 if( className.empty() )
10653 writeSection( name, "", *childNode, testOkToFail );
10654 else
10655 writeSection( className, name, *childNode, testOkToFail );
10656 }
10657
10658 void JunitReporter::writeAssertions( SectionNode const& sectionNode ) {
10659 for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
10660 if (assertionOrBenchmark.isAssertion()) {
10661 writeAssertion(assertionOrBenchmark.asAssertion());
10662 }
10663 }
10664 }
10665
10666 void JunitReporter::writeAssertion( AssertionStats const& stats ) {
10667 AssertionResult const& result = stats.assertionResult;
10668 if ( !result.isOk() ||
10669 result.getResultType() == ResultWas::ExplicitSkip ) {
10670 std::string elementName;
10671 switch( result.getResultType() ) {
10672 case ResultWas::ThrewException:
10673 case ResultWas::FatalErrorCondition:
10674 elementName = "error";
10675 break;
10676 case ResultWas::ExplicitFailure:
10677 case ResultWas::ExpressionFailed:
10678 case ResultWas::DidntThrowException:
10679 elementName = "failure";
10680 break;
10681 case ResultWas::ExplicitSkip:
10682 elementName = "skipped";
10683 break;
10684 // We should never see these here:
10685 case ResultWas::Info:
10686 case ResultWas::Warning:
10687 case ResultWas::Ok:
10688 case ResultWas::Unknown:
10689 case ResultWas::FailureBit:
10690 case ResultWas::Exception:
10691 elementName = "internalError";
10692 break;
10693 }
10694
10695 XmlWriter::ScopedElement e = xml.scopedElement( elementName );
10696
10697 xml.writeAttribute( "message"_sr, result.getExpression() );
10698 xml.writeAttribute( "type"_sr, result.getTestMacroName() );
10699
10700 ReusableStringStream rss;
10701 if ( result.getResultType() == ResultWas::ExplicitSkip ) {
10702 rss << "SKIPPED\n";
10703 } else {
10704 rss << "FAILED" << ":\n";
10705 if (result.hasExpression()) {
10706 rss << " ";
10707 rss << result.getExpressionInMacro();
10708 rss << '\n';
10709 }
10710 if (result.hasExpandedExpression()) {
10711 rss << "with expansion:\n";
10712 rss << TextFlow::Column(result.getExpandedExpression()).indent(2) << '\n';
10713 }
10714 }
10715
10716 if( result.hasMessage() )
10717 rss << result.getMessage() << '\n';
10718 for( auto const& msg : stats.infoMessages )
10719 if( msg.type == ResultWas::Info )
10720 rss << msg.message << '\n';
10721
10722 rss << "at " << result.getSourceInfo();
10723 xml.writeText( rss.str(), XmlFormatting::Newline );
10724 }
10725 }
10726
10727} // end namespace Catch
10728
10729
10730
10731
10732#include <ostream>
10733
10734namespace Catch {
10735 void MultiReporter::updatePreferences(IEventListener const& reporterish) {
10736 m_preferences.shouldRedirectStdOut |=
10737 reporterish.getPreferences().shouldRedirectStdOut;
10738 m_preferences.shouldReportAllAssertions |=
10739 reporterish.getPreferences().shouldReportAllAssertions;
10740 }
10741
10742 void MultiReporter::addListener( IEventListenerPtr&& listener ) {
10743 updatePreferences(*listener);
10744 m_reporterLikes.insert(m_reporterLikes.begin() + m_insertedListeners, CATCH_MOVE(listener) );
10745 ++m_insertedListeners;
10746 }
10747
10748 void MultiReporter::addReporter( IEventListenerPtr&& reporter ) {
10749 updatePreferences(*reporter);
10750
10751 // We will need to output the captured stdout if there are reporters
10752 // that do not want it captured.
10753 // We do not consider listeners, because it is generally assumed that
10754 // listeners are output-transparent, even though they can ask for stdout
10755 // capture to do something with it.
10756 m_haveNoncapturingReporters |= !reporter->getPreferences().shouldRedirectStdOut;
10757
10758 // Reporters can always be placed to the back without breaking the
10759 // reporting order
10760 m_reporterLikes.push_back( CATCH_MOVE( reporter ) );
10761 }
10762
10763 void MultiReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
10764 for ( auto& reporterish : m_reporterLikes ) {
10765 reporterish->noMatchingTestCases( unmatchedSpec );
10766 }
10767 }
10768
10769 void MultiReporter::fatalErrorEncountered( StringRef error ) {
10770 for ( auto& reporterish : m_reporterLikes ) {
10771 reporterish->fatalErrorEncountered( error );
10772 }
10773 }
10774
10775 void MultiReporter::reportInvalidTestSpec( StringRef arg ) {
10776 for ( auto& reporterish : m_reporterLikes ) {
10777 reporterish->reportInvalidTestSpec( arg );
10778 }
10779 }
10780
10781 void MultiReporter::benchmarkPreparing( StringRef name ) {
10782 for (auto& reporterish : m_reporterLikes) {
10783 reporterish->benchmarkPreparing(name);
10784 }
10785 }
10786 void MultiReporter::benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) {
10787 for ( auto& reporterish : m_reporterLikes ) {
10788 reporterish->benchmarkStarting( benchmarkInfo );
10789 }
10790 }
10791 void MultiReporter::benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) {
10792 for ( auto& reporterish : m_reporterLikes ) {
10793 reporterish->benchmarkEnded( benchmarkStats );
10794 }
10795 }
10796
10797 void MultiReporter::benchmarkFailed( StringRef error ) {
10798 for (auto& reporterish : m_reporterLikes) {
10799 reporterish->benchmarkFailed(error);
10800 }
10801 }
10802
10803 void MultiReporter::testRunStarting( TestRunInfo const& testRunInfo ) {
10804 for ( auto& reporterish : m_reporterLikes ) {
10805 reporterish->testRunStarting( testRunInfo );
10806 }
10807 }
10808
10809 void MultiReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
10810 for ( auto& reporterish : m_reporterLikes ) {
10811 reporterish->testCaseStarting( testInfo );
10812 }
10813 }
10814
10815 void
10816 MultiReporter::testCasePartialStarting( TestCaseInfo const& testInfo,
10817 uint64_t partNumber ) {
10818 for ( auto& reporterish : m_reporterLikes ) {
10819 reporterish->testCasePartialStarting( testInfo, partNumber );
10820 }
10821 }
10822
10823 void MultiReporter::sectionStarting( SectionInfo const& sectionInfo ) {
10824 for ( auto& reporterish : m_reporterLikes ) {
10825 reporterish->sectionStarting( sectionInfo );
10826 }
10827 }
10828
10829 void MultiReporter::assertionStarting( AssertionInfo const& assertionInfo ) {
10830 for ( auto& reporterish : m_reporterLikes ) {
10831 reporterish->assertionStarting( assertionInfo );
10832 }
10833 }
10834
10835 void MultiReporter::assertionEnded( AssertionStats const& assertionStats ) {
10836 const bool reportByDefault =
10837 assertionStats.assertionResult.getResultType() != ResultWas::Ok ||
10838 m_config->includeSuccessfulResults();
10839
10840 for ( auto & reporterish : m_reporterLikes ) {
10841 if ( reportByDefault ||
10842 reporterish->getPreferences().shouldReportAllAssertions ) {
10843 reporterish->assertionEnded( assertionStats );
10844 }
10845 }
10846 }
10847
10848 void MultiReporter::sectionEnded( SectionStats const& sectionStats ) {
10849 for ( auto& reporterish : m_reporterLikes ) {
10850 reporterish->sectionEnded( sectionStats );
10851 }
10852 }
10853
10854 void MultiReporter::testCasePartialEnded( TestCaseStats const& testStats,
10855 uint64_t partNumber ) {
10856 if ( m_preferences.shouldRedirectStdOut &&
10857 m_haveNoncapturingReporters ) {
10858 if ( !testStats.stdOut.empty() ) {
10859 Catch::cout() << testStats.stdOut << std::flush;
10860 }
10861 if ( !testStats.stdErr.empty() ) {
10862 Catch::cerr() << testStats.stdErr << std::flush;
10863 }
10864 }
10865
10866 for ( auto& reporterish : m_reporterLikes ) {
10867 reporterish->testCasePartialEnded( testStats, partNumber );
10868 }
10869 }
10870
10871 void MultiReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
10872 for ( auto& reporterish : m_reporterLikes ) {
10873 reporterish->testCaseEnded( testCaseStats );
10874 }
10875 }
10876
10877 void MultiReporter::testRunEnded( TestRunStats const& testRunStats ) {
10878 for ( auto& reporterish : m_reporterLikes ) {
10879 reporterish->testRunEnded( testRunStats );
10880 }
10881 }
10882
10883
10884 void MultiReporter::skipTest( TestCaseInfo const& testInfo ) {
10885 for ( auto& reporterish : m_reporterLikes ) {
10886 reporterish->skipTest( testInfo );
10887 }
10888 }
10889
10890 void MultiReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
10891 for (auto& reporterish : m_reporterLikes) {
10892 reporterish->listReporters(descriptions);
10893 }
10894 }
10895
10896 void MultiReporter::listListeners(
10897 std::vector<ListenerDescription> const& descriptions ) {
10898 for ( auto& reporterish : m_reporterLikes ) {
10899 reporterish->listListeners( descriptions );
10900 }
10901 }
10902
10903 void MultiReporter::listTests(std::vector<TestCaseHandle> const& tests) {
10904 for (auto& reporterish : m_reporterLikes) {
10905 reporterish->listTests(tests);
10906 }
10907 }
10908
10909 void MultiReporter::listTags(std::vector<TagInfo> const& tags) {
10910 for (auto& reporterish : m_reporterLikes) {
10911 reporterish->listTags(tags);
10912 }
10913 }
10914
10915} // end namespace Catch
10916
10917
10918
10919
10920
10921namespace Catch {
10922 namespace Detail {
10923
10924 void registerReporterImpl( std::string const& name,
10925 IReporterFactoryPtr reporterPtr ) {
10926 CATCH_TRY {
10927 getMutableRegistryHub().registerReporter(
10928 name, CATCH_MOVE( reporterPtr ) );
10929 }
10930 CATCH_CATCH_ALL {
10931 // Do not throw when constructing global objects, instead
10932 // register the exception to be processed later
10933 getMutableRegistryHub().registerStartupException();
10934 }
10935 }
10936
10937 void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory ) {
10938 getMutableRegistryHub().registerListener( CATCH_MOVE(listenerFactory) );
10939 }
10940
10941
10942 } // namespace Detail
10943} // namespace Catch
10944
10945
10946
10947
10948#include <map>
10949
10950namespace Catch {
10951
10952 namespace {
10953 std::string createMetadataString(IConfig const& config) {
10954 ReusableStringStream sstr;
10955 if ( config.testSpec().hasFilters() ) {
10956 sstr << "filters='"
10957 << config.testSpec()
10958 << "' ";
10959 }
10960 sstr << "rng-seed=" << config.rngSeed();
10961 return sstr.str();
10962 }
10963 }
10964
10965 void SonarQubeReporter::testRunStarting(TestRunInfo const& testRunInfo) {
10966 CumulativeReporterBase::testRunStarting(testRunInfo);
10967
10968 xml.writeComment( createMetadataString( *m_config ) );
10969 xml.startElement("testExecutions");
10970 xml.writeAttribute("version"_sr, '1');
10971 }
10972
10973 void SonarQubeReporter::writeRun( TestRunNode const& runNode ) {
10974 std::map<StringRef, std::vector<TestCaseNode const*>> testsPerFile;
10975
10976 for ( auto const& child : runNode.children ) {
10977 testsPerFile[child->value.testInfo->lineInfo.file].push_back(
10978 child.get() );
10979 }
10980
10981 for ( auto const& kv : testsPerFile ) {
10982 writeTestFile( kv.first, kv.second );
10983 }
10984 }
10985
10986 void SonarQubeReporter::writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes) {
10987 XmlWriter::ScopedElement e = xml.scopedElement("file");
10988 xml.writeAttribute("path"_sr, filename);
10989
10990 for (auto const& child : testCaseNodes)
10991 writeTestCase(*child);
10992 }
10993
10994 void SonarQubeReporter::writeTestCase(TestCaseNode const& testCaseNode) {
10995 // All test cases have exactly one section - which represents the
10996 // test case itself. That section may have 0-n nested sections
10997 assert(testCaseNode.children.size() == 1);
10998 SectionNode const& rootSection = *testCaseNode.children.front();
10999 writeSection("", rootSection, testCaseNode.value.testInfo->okToFail());
11000 }
11001
11002 void SonarQubeReporter::writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail) {
11003 std::string name = trim(sectionNode.stats.sectionInfo.name);
11004 if (!rootName.empty())
11005 name = rootName + '/' + name;
11006
11007 if ( sectionNode.stats.assertions.total() > 0
11008 || !sectionNode.stdOut.empty()
11009 || !sectionNode.stdErr.empty() ) {
11010 XmlWriter::ScopedElement e = xml.scopedElement("testCase");
11011 xml.writeAttribute("name"_sr, name);
11012 xml.writeAttribute("duration"_sr, static_cast<long>(sectionNode.stats.durationInSeconds * 1000));
11013
11014 writeAssertions(sectionNode, okToFail);
11015 }
11016
11017 for (auto const& childNode : sectionNode.childSections)
11018 writeSection(name, *childNode, okToFail);
11019 }
11020
11021 void SonarQubeReporter::writeAssertions(SectionNode const& sectionNode, bool okToFail) {
11022 for (auto const& assertionOrBenchmark : sectionNode.assertionsAndBenchmarks) {
11023 if (assertionOrBenchmark.isAssertion()) {
11024 writeAssertion(assertionOrBenchmark.asAssertion(), okToFail);
11025 }
11026 }
11027 }
11028
11029 void SonarQubeReporter::writeAssertion(AssertionStats const& stats, bool okToFail) {
11030 AssertionResult const& result = stats.assertionResult;
11031 if ( !result.isOk() ||
11032 result.getResultType() == ResultWas::ExplicitSkip ) {
11033 std::string elementName;
11034 if (okToFail) {
11035 elementName = "skipped";
11036 } else {
11037 switch (result.getResultType()) {
11038 case ResultWas::ThrewException:
11039 case ResultWas::FatalErrorCondition:
11040 elementName = "error";
11041 break;
11042 case ResultWas::ExplicitFailure:
11043 case ResultWas::ExpressionFailed:
11044 case ResultWas::DidntThrowException:
11045 elementName = "failure";
11046 break;
11047 case ResultWas::ExplicitSkip:
11048 elementName = "skipped";
11049 break;
11050 // We should never see these here:
11051 case ResultWas::Info:
11052 case ResultWas::Warning:
11053 case ResultWas::Ok:
11054 case ResultWas::Unknown:
11055 case ResultWas::FailureBit:
11056 case ResultWas::Exception:
11057 elementName = "internalError";
11058 break;
11059 }
11060 }
11061
11062 XmlWriter::ScopedElement e = xml.scopedElement(elementName);
11063
11064 ReusableStringStream messageRss;
11065 messageRss << result.getTestMacroName() << '(' << result.getExpression() << ')';
11066 xml.writeAttribute("message"_sr, messageRss.str());
11067
11068 ReusableStringStream textRss;
11069 if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11070 textRss << "SKIPPED\n";
11071 } else {
11072 textRss << "FAILED:\n";
11073 if (result.hasExpression()) {
11074 textRss << '\t' << result.getExpressionInMacro() << '\n';
11075 }
11076 if (result.hasExpandedExpression()) {
11077 textRss << "with expansion:\n\t" << result.getExpandedExpression() << '\n';
11078 }
11079 }
11080
11081 if (result.hasMessage())
11082 textRss << result.getMessage() << '\n';
11083
11084 for (auto const& msg : stats.infoMessages)
11085 if (msg.type == ResultWas::Info)
11086 textRss << msg.message << '\n';
11087
11088 textRss << "at " << result.getSourceInfo();
11089 xml.writeText(textRss.str(), XmlFormatting::Newline);
11090 }
11091 }
11092
11093} // end namespace Catch
11094
11095
11096
11097namespace Catch {
11098
11099 StreamingReporterBase::~StreamingReporterBase() = default;
11100
11101 void
11102 StreamingReporterBase::testRunStarting( TestRunInfo const& _testRunInfo ) {
11103 currentTestRunInfo = _testRunInfo;
11104 }
11105
11106 void StreamingReporterBase::testRunEnded( TestRunStats const& ) {
11107 currentTestCaseInfo = nullptr;
11108 }
11109
11110} // end namespace Catch
11111
11112
11113
11114#include <algorithm>
11115#include <ostream>
11116
11117namespace Catch {
11118
11119 namespace {
11120 // Yes, this has to be outside the class and namespaced by naming.
11121 // Making older compiler happy is hard.
11122 static constexpr StringRef tapFailedString = "not ok"_sr;
11123 static constexpr StringRef tapPassedString = "ok"_sr;
11124 static constexpr Colour::Code tapDimColour = Colour::FileName;
11125
11126 class TapAssertionPrinter {
11127 public:
11128 TapAssertionPrinter& operator= (TapAssertionPrinter const&) = delete;
11129 TapAssertionPrinter(TapAssertionPrinter const&) = delete;
11130 TapAssertionPrinter(std::ostream& _stream, AssertionStats const& _stats, std::size_t _counter, ColourImpl* colour_)
11131 : stream(_stream)
11132 , result(_stats.assertionResult)
11133 , messages(_stats.infoMessages)
11134 , itMessage(_stats.infoMessages.begin())
11135 , printInfoMessages(true)
11136 , counter(_counter)
11137 , colourImpl( colour_ ) {}
11138
11139 void print() {
11140 itMessage = messages.begin();
11141
11142 switch (result.getResultType()) {
11143 case ResultWas::Ok:
11144 printResultType(tapPassedString);
11145 printOriginalExpression();
11146 printReconstructedExpression();
11147 if (!result.hasExpression())
11148 printRemainingMessages(Colour::None);
11149 else
11150 printRemainingMessages();
11151 break;
11152 case ResultWas::ExpressionFailed:
11153 if (result.isOk()) {
11154 printResultType(tapPassedString);
11155 } else {
11156 printResultType(tapFailedString);
11157 }
11158 printOriginalExpression();
11159 printReconstructedExpression();
11160 if (result.isOk()) {
11161 printIssue(" # TODO");
11162 }
11163 printRemainingMessages();
11164 break;
11165 case ResultWas::ThrewException:
11166 printResultType(tapFailedString);
11167 printIssue("unexpected exception with message:"_sr);
11168 printMessage();
11169 printExpressionWas();
11170 printRemainingMessages();
11171 break;
11172 case ResultWas::FatalErrorCondition:
11173 printResultType(tapFailedString);
11174 printIssue("fatal error condition with message:"_sr);
11175 printMessage();
11176 printExpressionWas();
11177 printRemainingMessages();
11178 break;
11179 case ResultWas::DidntThrowException:
11180 printResultType(tapFailedString);
11181 printIssue("expected exception, got none"_sr);
11182 printExpressionWas();
11183 printRemainingMessages();
11184 break;
11185 case ResultWas::Info:
11186 printResultType("info"_sr);
11187 printMessage();
11188 printRemainingMessages();
11189 break;
11190 case ResultWas::Warning:
11191 printResultType("warning"_sr);
11192 printMessage();
11193 printRemainingMessages();
11194 break;
11195 case ResultWas::ExplicitFailure:
11196 printResultType(tapFailedString);
11197 printIssue("explicitly"_sr);
11198 printRemainingMessages(Colour::None);
11199 break;
11200 case ResultWas::ExplicitSkip:
11201 printResultType(tapPassedString);
11202 printIssue(" # SKIP"_sr);
11203 printMessage();
11204 printRemainingMessages();
11205 break;
11206 // These cases are here to prevent compiler warnings
11207 case ResultWas::Unknown:
11208 case ResultWas::FailureBit:
11209 case ResultWas::Exception:
11210 printResultType("** internal error **"_sr);
11211 break;
11212 }
11213 }
11214
11215 private:
11216 void printResultType(StringRef passOrFail) const {
11217 if (!passOrFail.empty()) {
11218 stream << passOrFail << ' ' << counter << " -";
11219 }
11220 }
11221
11222 void printIssue(StringRef issue) const {
11223 stream << ' ' << issue;
11224 }
11225
11226 void printExpressionWas() {
11227 if (result.hasExpression()) {
11228 stream << ';';
11229 stream << colourImpl->guardColour( tapDimColour )
11230 << " expression was:";
11231 printOriginalExpression();
11232 }
11233 }
11234
11235 void printOriginalExpression() const {
11236 if (result.hasExpression()) {
11237 stream << ' ' << result.getExpression();
11238 }
11239 }
11240
11241 void printReconstructedExpression() const {
11242 if (result.hasExpandedExpression()) {
11243 stream << colourImpl->guardColour( tapDimColour ) << " for: ";
11244
11245 std::string expr = result.getExpandedExpression();
11246 std::replace(expr.begin(), expr.end(), '\n', ' ');
11247 stream << expr;
11248 }
11249 }
11250
11251 void printMessage() {
11252 if (itMessage != messages.end()) {
11253 stream << " '" << itMessage->message << '\'';
11254 ++itMessage;
11255 }
11256 }
11257
11258 void printRemainingMessages(Colour::Code colour = tapDimColour) {
11259 if (itMessage == messages.end()) {
11260 return;
11261 }
11262
11263 // using messages.end() directly (or auto) yields compilation error:
11264 std::vector<MessageInfo>::const_iterator itEnd = messages.end();
11265 const std::size_t N = static_cast<std::size_t>(itEnd - itMessage);
11266
11267 stream << colourImpl->guardColour( colour ) << " with "
11268 << pluralise( N, "message"_sr ) << ':';
11269
11270 for (; itMessage != itEnd; ) {
11271 // If this assertion is a warning ignore any INFO messages
11272 if (printInfoMessages || itMessage->type != ResultWas::Info) {
11273 stream << " '" << itMessage->message << '\'';
11274 if (++itMessage != itEnd) {
11275 stream << colourImpl->guardColour(tapDimColour) << " and";
11276 }
11277 }
11278 }
11279 }
11280
11281 private:
11282 std::ostream& stream;
11283 AssertionResult const& result;
11284 std::vector<MessageInfo> const& messages;
11285 std::vector<MessageInfo>::const_iterator itMessage;
11286 bool printInfoMessages;
11287 std::size_t counter;
11288 ColourImpl* colourImpl;
11289 };
11290
11291 } // End anonymous namespace
11292
11293 void TAPReporter::testRunStarting( TestRunInfo const& ) {
11294 if ( m_config->testSpec().hasFilters() ) {
11295 m_stream << "# filters: " << m_config->testSpec() << '\n';
11296 }
11297 m_stream << "# rng-seed: " << m_config->rngSeed() << '\n';
11298 }
11299
11300 void TAPReporter::noMatchingTestCases( StringRef unmatchedSpec ) {
11301 m_stream << "# No test cases matched '" << unmatchedSpec << "'\n";
11302 }
11303
11304 void TAPReporter::assertionEnded(AssertionStats const& _assertionStats) {
11305 ++counter;
11306
11307 m_stream << "# " << currentTestCaseInfo->name << '\n';
11308 TapAssertionPrinter printer(m_stream, _assertionStats, counter, m_colour.get());
11309 printer.print();
11310
11311 m_stream << '\n' << std::flush;
11312 }
11313
11314 void TAPReporter::testRunEnded(TestRunStats const& _testRunStats) {
11315 m_stream << "1.." << _testRunStats.totals.assertions.total();
11316 if (_testRunStats.totals.testCases.total() == 0) {
11317 m_stream << " # Skipped: No tests ran.";
11318 }
11319 m_stream << "\n\n" << std::flush;
11320 StreamingReporterBase::testRunEnded(_testRunStats);
11321 }
11322
11323
11324
11325
11326} // end namespace Catch
11327
11328
11329
11330
11331#include <cassert>
11332#include <ostream>
11333
11334namespace Catch {
11335
11336 namespace {
11337 // if string has a : in first line will set indent to follow it on
11338 // subsequent lines
11339 void printHeaderString(std::ostream& os, std::string const& _string, std::size_t indent = 0) {
11340 std::size_t i = _string.find(": ");
11341 if (i != std::string::npos)
11342 i += 2;
11343 else
11344 i = 0;
11345 os << TextFlow::Column(_string)
11346 .indent(indent + i)
11347 .initialIndent(indent) << '\n';
11348 }
11349
11350 std::string escape(StringRef str) {
11351 std::string escaped = static_cast<std::string>(str);
11352 replaceInPlace(escaped, "|", "||");
11353 replaceInPlace(escaped, "'", "|'");
11354 replaceInPlace(escaped, "\n", "|n");
11355 replaceInPlace(escaped, "\r", "|r");
11356 replaceInPlace(escaped, "[", "|[");
11357 replaceInPlace(escaped, "]", "|]");
11358 return escaped;
11359 }
11360 } // end anonymous namespace
11361
11362
11363 TeamCityReporter::~TeamCityReporter() = default;
11364
11365 void TeamCityReporter::testRunStarting( TestRunInfo const& runInfo ) {
11366 m_stream << "##teamcity[testSuiteStarted name='" << escape( runInfo.name )
11367 << "']\n";
11368 }
11369
11370 void TeamCityReporter::testRunEnded( TestRunStats const& runStats ) {
11371 m_stream << "##teamcity[testSuiteFinished name='"
11372 << escape( runStats.runInfo.name ) << "']\n";
11373 }
11374
11375 void TeamCityReporter::assertionEnded(AssertionStats const& assertionStats) {
11376 AssertionResult const& result = assertionStats.assertionResult;
11377 if ( !result.isOk() ||
11378 result.getResultType() == ResultWas::ExplicitSkip ) {
11379
11380 ReusableStringStream msg;
11381 if (!m_headerPrintedForThisSection)
11382 printSectionHeader(msg.get());
11383 m_headerPrintedForThisSection = true;
11384
11385 msg << result.getSourceInfo() << '\n';
11386
11387 switch (result.getResultType()) {
11388 case ResultWas::ExpressionFailed:
11389 msg << "expression failed";
11390 break;
11391 case ResultWas::ThrewException:
11392 msg << "unexpected exception";
11393 break;
11394 case ResultWas::FatalErrorCondition:
11395 msg << "fatal error condition";
11396 break;
11397 case ResultWas::DidntThrowException:
11398 msg << "no exception was thrown where one was expected";
11399 break;
11400 case ResultWas::ExplicitFailure:
11401 msg << "explicit failure";
11402 break;
11403 case ResultWas::ExplicitSkip:
11404 msg << "explicit skip";
11405 break;
11406
11407 // We shouldn't get here because of the isOk() test
11408 case ResultWas::Ok:
11409 case ResultWas::Info:
11410 case ResultWas::Warning:
11411 CATCH_ERROR("Internal error in TeamCity reporter");
11412 // These cases are here to prevent compiler warnings
11413 case ResultWas::Unknown:
11414 case ResultWas::FailureBit:
11415 case ResultWas::Exception:
11416 CATCH_ERROR("Not implemented");
11417 }
11418 if (assertionStats.infoMessages.size() == 1)
11419 msg << " with message:";
11420 if (assertionStats.infoMessages.size() > 1)
11421 msg << " with messages:";
11422 for (auto const& messageInfo : assertionStats.infoMessages)
11423 msg << "\n \"" << messageInfo.message << '"';
11424
11425
11426 if (result.hasExpression()) {
11427 msg <<
11428 "\n " << result.getExpressionInMacro() << "\n"
11429 "with expansion:\n"
11430 " " << result.getExpandedExpression() << '\n';
11431 }
11432
11433 if ( result.getResultType() == ResultWas::ExplicitSkip ) {
11434 m_stream << "##teamcity[testIgnored";
11435 } else if ( currentTestCaseInfo->okToFail() ) {
11436 msg << "- failure ignore as test marked as 'ok to fail'\n";
11437 m_stream << "##teamcity[testIgnored";
11438 } else {
11439 m_stream << "##teamcity[testFailed";
11440 }
11441 m_stream << " name='" << escape( currentTestCaseInfo->name ) << '\''
11442 << " message='" << escape( msg.str() ) << '\'' << "]\n";
11443 }
11444 m_stream.flush();
11445 }
11446
11447 void TeamCityReporter::testCaseStarting(TestCaseInfo const& testInfo) {
11448 m_testTimer.start();
11449 StreamingReporterBase::testCaseStarting(testInfo);
11450 m_stream << "##teamcity[testStarted name='"
11451 << escape(testInfo.name) << "']\n";
11452 m_stream.flush();
11453 }
11454
11455 void TeamCityReporter::testCaseEnded(TestCaseStats const& testCaseStats) {
11456 StreamingReporterBase::testCaseEnded(testCaseStats);
11457 auto const& testCaseInfo = *testCaseStats.testInfo;
11458 if (!testCaseStats.stdOut.empty())
11459 m_stream << "##teamcity[testStdOut name='"
11460 << escape(testCaseInfo.name)
11461 << "' out='" << escape(testCaseStats.stdOut) << "']\n";
11462 if (!testCaseStats.stdErr.empty())
11463 m_stream << "##teamcity[testStdErr name='"
11464 << escape(testCaseInfo.name)
11465 << "' out='" << escape(testCaseStats.stdErr) << "']\n";
11466 m_stream << "##teamcity[testFinished name='"
11467 << escape(testCaseInfo.name) << "' duration='"
11468 << m_testTimer.getElapsedMilliseconds() << "']\n";
11469 m_stream.flush();
11470 }
11471
11472 void TeamCityReporter::printSectionHeader(std::ostream& os) {
11473 assert(!m_sectionStack.empty());
11474
11475 if (m_sectionStack.size() > 1) {
11476 os << lineOfChars('-') << '\n';
11477
11478 std::vector<SectionInfo>::const_iterator
11479 it = m_sectionStack.begin() + 1, // Skip first section (test case)
11480 itEnd = m_sectionStack.end();
11481 for (; it != itEnd; ++it)
11482 printHeaderString(os, it->name);
11483 os << lineOfChars('-') << '\n';
11484 }
11485
11486 SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
11487
11488 os << lineInfo << '\n';
11489 os << lineOfChars('.') << "\n\n";
11490 }
11491
11492} // end namespace Catch
11493
11494
11495
11496
11497#if defined(_MSC_VER)
11498#pragma warning(push)
11499#pragma warning(disable:4061) // Not all labels are EXPLICITLY handled in switch
11500 // Note that 4062 (not all labels are handled
11501 // and default is missing) is enabled
11502#endif
11503
11504namespace Catch {
11505 XmlReporter::XmlReporter( ReporterConfig&& _config )
11506 : StreamingReporterBase( CATCH_MOVE(_config) ),
11507 m_xml(m_stream)
11508 {
11509 m_preferences.shouldRedirectStdOut = true;
11510 m_preferences.shouldReportAllAssertions = true;
11511 }
11512
11513 XmlReporter::~XmlReporter() = default;
11514
11515 std::string XmlReporter::getDescription() {
11516 return "Reports test results as an XML document";
11517 }
11518
11519 std::string XmlReporter::getStylesheetRef() const {
11520 return std::string();
11521 }
11522
11523 void XmlReporter::writeSourceInfo( SourceLineInfo const& sourceInfo ) {
11524 m_xml
11525 .writeAttribute( "filename"_sr, sourceInfo.file )
11526 .writeAttribute( "line"_sr, sourceInfo.line );
11527 }
11528
11529 void XmlReporter::testRunStarting( TestRunInfo const& testInfo ) {
11530 StreamingReporterBase::testRunStarting( testInfo );
11531 std::string stylesheetRef = getStylesheetRef();
11532 if( !stylesheetRef.empty() )
11533 m_xml.writeStylesheetRef( stylesheetRef );
11534 m_xml.startElement("Catch2TestRun")
11535 .writeAttribute("name"_sr, m_config->name())
11536 .writeAttribute("rng-seed"_sr, m_config->rngSeed())
11537 .writeAttribute("xml-format-version"_sr, 3)
11538 .writeAttribute("catch2-version"_sr, libraryVersion());
11539 if ( m_config->testSpec().hasFilters() ) {
11540 m_xml.writeAttribute( "filters"_sr, m_config->testSpec() );
11541 }
11542 }
11543
11544 void XmlReporter::testCaseStarting( TestCaseInfo const& testInfo ) {
11545 StreamingReporterBase::testCaseStarting(testInfo);
11546 m_xml.startElement( "TestCase" )
11547 .writeAttribute( "name"_sr, trim( StringRef(testInfo.name) ) )
11548 .writeAttribute( "tags"_sr, testInfo.tagsAsString() );
11549
11550 writeSourceInfo( testInfo.lineInfo );
11551
11552 if ( m_config->showDurations() == ShowDurations::Always )
11553 m_testCaseTimer.start();
11554 m_xml.ensureTagClosed();
11555 }
11556
11557 void XmlReporter::sectionStarting( SectionInfo const& sectionInfo ) {
11558 StreamingReporterBase::sectionStarting( sectionInfo );
11559 if( m_sectionDepth++ > 0 ) {
11560 m_xml.startElement( "Section" )
11561 .writeAttribute( "name"_sr, trim( StringRef(sectionInfo.name) ) );
11562 writeSourceInfo( sectionInfo.lineInfo );
11563 m_xml.ensureTagClosed();
11564 }
11565 }
11566
11567 void XmlReporter::assertionStarting( AssertionInfo const& ) { }
11568
11569 void XmlReporter::assertionEnded( AssertionStats const& assertionStats ) {
11570
11571 AssertionResult const& result = assertionStats.assertionResult;
11572
11573 bool includeResults = m_config->includeSuccessfulResults() || !result.isOk();
11574
11575 if( includeResults || result.getResultType() == ResultWas::Warning ) {
11576 // Print any info messages in <Info> tags.
11577 for( auto const& msg : assertionStats.infoMessages ) {
11578 if( msg.type == ResultWas::Info && includeResults ) {
11579 auto t = m_xml.scopedElement( "Info" );
11580 writeSourceInfo( msg.lineInfo );
11581 t.writeText( msg.message );
11582 } else if ( msg.type == ResultWas::Warning ) {
11583 auto t = m_xml.scopedElement( "Warning" );
11584 writeSourceInfo( msg.lineInfo );
11585 t.writeText( msg.message );
11586 }
11587 }
11588 }
11589
11590 // Drop out if result was successful but we're not printing them.
11591 if ( !includeResults && result.getResultType() != ResultWas::Warning &&
11592 result.getResultType() != ResultWas::ExplicitSkip ) {
11593 return;
11594 }
11595
11596 // Print the expression if there is one.
11597 if( result.hasExpression() ) {
11598 m_xml.startElement( "Expression" )
11599 .writeAttribute( "success"_sr, result.succeeded() )
11600 .writeAttribute( "type"_sr, result.getTestMacroName() );
11601
11602 writeSourceInfo( result.getSourceInfo() );
11603
11604 m_xml.scopedElement( "Original" )
11605 .writeText( result.getExpression() );
11606 m_xml.scopedElement( "Expanded" )
11607 .writeText( result.getExpandedExpression() );
11608 }
11609
11610 // And... Print a result applicable to each result type.
11611 switch( result.getResultType() ) {
11612 case ResultWas::ThrewException:
11613 m_xml.startElement( "Exception" );
11614 writeSourceInfo( result.getSourceInfo() );
11615 m_xml.writeText( result.getMessage() );
11616 m_xml.endElement();
11617 break;
11618 case ResultWas::FatalErrorCondition:
11619 m_xml.startElement( "FatalErrorCondition" );
11620 writeSourceInfo( result.getSourceInfo() );
11621 m_xml.writeText( result.getMessage() );
11622 m_xml.endElement();
11623 break;
11624 case ResultWas::Info:
11625 m_xml.scopedElement( "Info" )
11626 .writeText( result.getMessage() );
11627 break;
11628 case ResultWas::Warning:
11629 // Warning will already have been written
11630 break;
11631 case ResultWas::ExplicitFailure:
11632 m_xml.startElement( "Failure" );
11633 writeSourceInfo( result.getSourceInfo() );
11634 m_xml.writeText( result.getMessage() );
11635 m_xml.endElement();
11636 break;
11637 case ResultWas::ExplicitSkip:
11638 m_xml.startElement( "Skip" );
11639 writeSourceInfo( result.getSourceInfo() );
11640 m_xml.writeText( result.getMessage() );
11641 m_xml.endElement();
11642 break;
11643 default:
11644 break;
11645 }
11646
11647 if( result.hasExpression() )
11648 m_xml.endElement();
11649 }
11650
11651 void XmlReporter::sectionEnded( SectionStats const& sectionStats ) {
11652 StreamingReporterBase::sectionEnded( sectionStats );
11653 if ( --m_sectionDepth > 0 ) {
11654 {
11655 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResults" );
11656 e.writeAttribute( "successes"_sr, sectionStats.assertions.passed );
11657 e.writeAttribute( "failures"_sr, sectionStats.assertions.failed );
11658 e.writeAttribute( "expectedFailures"_sr, sectionStats.assertions.failedButOk );
11659 e.writeAttribute( "skipped"_sr, sectionStats.assertions.skipped > 0 );
11660
11661 if ( m_config->showDurations() == ShowDurations::Always )
11662 e.writeAttribute( "durationInSeconds"_sr, sectionStats.durationInSeconds );
11663 }
11664 // Ends assertion tag
11665 m_xml.endElement();
11666 }
11667 }
11668
11669 void XmlReporter::testCaseEnded( TestCaseStats const& testCaseStats ) {
11670 StreamingReporterBase::testCaseEnded( testCaseStats );
11671 XmlWriter::ScopedElement e = m_xml.scopedElement( "OverallResult" );
11672 e.writeAttribute( "success"_sr, testCaseStats.totals.assertions.allOk() );
11673 e.writeAttribute( "skips"_sr, testCaseStats.totals.assertions.skipped );
11674
11675 if ( m_config->showDurations() == ShowDurations::Always )
11676 e.writeAttribute( "durationInSeconds"_sr, m_testCaseTimer.getElapsedSeconds() );
11677 if( !testCaseStats.stdOut.empty() )
11678 m_xml.scopedElement( "StdOut" ).writeText( trim( StringRef(testCaseStats.stdOut) ), XmlFormatting::Newline );
11679 if( !testCaseStats.stdErr.empty() )
11680 m_xml.scopedElement( "StdErr" ).writeText( trim( StringRef(testCaseStats.stdErr) ), XmlFormatting::Newline );
11681
11682 m_xml.endElement();
11683 }
11684
11685 void XmlReporter::testRunEnded( TestRunStats const& testRunStats ) {
11686 StreamingReporterBase::testRunEnded( testRunStats );
11687 m_xml.scopedElement( "OverallResults" )
11688 .writeAttribute( "successes"_sr, testRunStats.totals.assertions.passed )
11689 .writeAttribute( "failures"_sr, testRunStats.totals.assertions.failed )
11690 .writeAttribute( "expectedFailures"_sr, testRunStats.totals.assertions.failedButOk )
11691 .writeAttribute( "skips"_sr, testRunStats.totals.assertions.skipped );
11692 m_xml.scopedElement( "OverallResultsCases")
11693 .writeAttribute( "successes"_sr, testRunStats.totals.testCases.passed )
11694 .writeAttribute( "failures"_sr, testRunStats.totals.testCases.failed )
11695 .writeAttribute( "expectedFailures"_sr, testRunStats.totals.testCases.failedButOk )
11696 .writeAttribute( "skips"_sr, testRunStats.totals.testCases.skipped );
11697 m_xml.endElement();
11698 }
11699
11700 void XmlReporter::benchmarkPreparing( StringRef name ) {
11701 m_xml.startElement("BenchmarkResults")
11702 .writeAttribute("name"_sr, name);
11703 }
11704
11705 void XmlReporter::benchmarkStarting(BenchmarkInfo const &info) {
11706 m_xml.writeAttribute("samples"_sr, info.samples)
11707 .writeAttribute("resamples"_sr, info.resamples)
11708 .writeAttribute("iterations"_sr, info.iterations)
11709 .writeAttribute("clockResolution"_sr, info.clockResolution)
11710 .writeAttribute("estimatedDuration"_sr, info.estimatedDuration)
11711 .writeComment("All values in nano seconds"_sr);
11712 }
11713
11714 void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) {
11715 m_xml.scopedElement("mean")
11716 .writeAttribute("value"_sr, benchmarkStats.mean.point.count())
11717 .writeAttribute("lowerBound"_sr, benchmarkStats.mean.lower_bound.count())
11718 .writeAttribute("upperBound"_sr, benchmarkStats.mean.upper_bound.count())
11719 .writeAttribute("ci"_sr, benchmarkStats.mean.confidence_interval);
11720 m_xml.scopedElement("standardDeviation")
11721 .writeAttribute("value"_sr, benchmarkStats.standardDeviation.point.count())
11722 .writeAttribute("lowerBound"_sr, benchmarkStats.standardDeviation.lower_bound.count())
11723 .writeAttribute("upperBound"_sr, benchmarkStats.standardDeviation.upper_bound.count())
11724 .writeAttribute("ci"_sr, benchmarkStats.standardDeviation.confidence_interval);
11725 m_xml.scopedElement("outliers")
11726 .writeAttribute("variance"_sr, benchmarkStats.outlierVariance)
11727 .writeAttribute("lowMild"_sr, benchmarkStats.outliers.low_mild)
11728 .writeAttribute("lowSevere"_sr, benchmarkStats.outliers.low_severe)
11729 .writeAttribute("highMild"_sr, benchmarkStats.outliers.high_mild)
11730 .writeAttribute("highSevere"_sr, benchmarkStats.outliers.high_severe);
11731 m_xml.endElement();
11732 }
11733
11734 void XmlReporter::benchmarkFailed(StringRef error) {
11735 m_xml.scopedElement("failed").
11736 writeAttribute("message"_sr, error);
11737 m_xml.endElement();
11738 }
11739
11740 void XmlReporter::listReporters(std::vector<ReporterDescription> const& descriptions) {
11741 auto outerTag = m_xml.scopedElement("AvailableReporters");
11742 for (auto const& reporter : descriptions) {
11743 auto inner = m_xml.scopedElement("Reporter");
11744 m_xml.startElement("Name", XmlFormatting::Indent)
11745 .writeText(reporter.name, XmlFormatting::None)
11746 .endElement(XmlFormatting::Newline);
11747 m_xml.startElement("Description", XmlFormatting::Indent)
11748 .writeText(reporter.description, XmlFormatting::None)
11749 .endElement(XmlFormatting::Newline);
11750 }
11751 }
11752
11753 void XmlReporter::listListeners(std::vector<ListenerDescription> const& descriptions) {
11754 auto outerTag = m_xml.scopedElement( "RegisteredListeners" );
11755 for ( auto const& listener : descriptions ) {
11756 auto inner = m_xml.scopedElement( "Listener" );
11757 m_xml.startElement( "Name", XmlFormatting::Indent )
11758 .writeText( listener.name, XmlFormatting::None )
11759 .endElement( XmlFormatting::Newline );
11760 m_xml.startElement( "Description", XmlFormatting::Indent )
11761 .writeText( listener.description, XmlFormatting::None )
11762 .endElement( XmlFormatting::Newline );
11763 }
11764 }
11765
11766 void XmlReporter::listTests(std::vector<TestCaseHandle> const& tests) {
11767 auto outerTag = m_xml.scopedElement("MatchingTests");
11768 for (auto const& test : tests) {
11769 auto innerTag = m_xml.scopedElement("TestCase");
11770 auto const& testInfo = test.getTestCaseInfo();
11771 m_xml.startElement("Name", XmlFormatting::Indent)
11772 .writeText(testInfo.name, XmlFormatting::None)
11773 .endElement(XmlFormatting::Newline);
11774 m_xml.startElement("ClassName", XmlFormatting::Indent)
11775 .writeText(testInfo.className, XmlFormatting::None)
11776 .endElement(XmlFormatting::Newline);
11777 m_xml.startElement("Tags", XmlFormatting::Indent)
11778 .writeText(testInfo.tagsAsString(), XmlFormatting::None)
11779 .endElement(XmlFormatting::Newline);
11780
11781 auto sourceTag = m_xml.scopedElement("SourceInfo");
11782 m_xml.startElement("File", XmlFormatting::Indent)
11783 .writeText(testInfo.lineInfo.file, XmlFormatting::None)
11784 .endElement(XmlFormatting::Newline);
11785 m_xml.startElement("Line", XmlFormatting::Indent)
11786 .writeText(std::to_string(testInfo.lineInfo.line), XmlFormatting::None)
11787 .endElement(XmlFormatting::Newline);
11788 }
11789 }
11790
11791 void XmlReporter::listTags(std::vector<TagInfo> const& tags) {
11792 auto outerTag = m_xml.scopedElement("TagsFromMatchingTests");
11793 for (auto const& tag : tags) {
11794 auto innerTag = m_xml.scopedElement("Tag");
11795 m_xml.startElement("Count", XmlFormatting::Indent)
11796 .writeText(std::to_string(tag.count), XmlFormatting::None)
11797 .endElement(XmlFormatting::Newline);
11798 auto aliasTag = m_xml.scopedElement("Aliases");
11799 for (auto const& alias : tag.spellings) {
11800 m_xml.startElement("Alias", XmlFormatting::Indent)
11801 .writeText(alias, XmlFormatting::None)
11802 .endElement(XmlFormatting::Newline);
11803 }
11804 }
11805 }
11806
11807} // end namespace Catch
11808
11809#if defined(_MSC_VER)
11810#pragma warning(pop)
11811#endif
diff --git a/unit_tests/catch_amalgamated.hpp b/unit_tests/catch_amalgamated.hpp
new file mode 100644
index 0000000..b7c768b
--- /dev/null
+++ b/unit_tests/catch_amalgamated.hpp
@@ -0,0 +1,14106 @@
1
2// Copyright Catch2 Authors
3// Distributed under the Boost Software License, Version 1.0.
4// (See accompanying file LICENSE.txt or copy at
5// https://www.boost.org/LICENSE_1_0.txt)
6
7// SPDX-License-Identifier: BSL-1.0
8
9// Catch v3.7.1
10// Generated: 2024-09-17 10:36:40.974985
11// ----------------------------------------------------------
12// This file is an amalgamation of multiple different files.
13// You probably shouldn't edit it directly.
14// ----------------------------------------------------------
15#ifndef CATCH_AMALGAMATED_HPP_INCLUDED
16#define CATCH_AMALGAMATED_HPP_INCLUDED
17
18
19/** \file
20 * This is a convenience header for Catch2. It includes **all** of Catch2 headers.
21 *
22 * Generally the Catch2 users should use specific includes they need,
23 * but this header can be used instead for ease-of-experimentation, or
24 * just plain convenience, at the cost of (significantly) increased
25 * compilation times.
26 *
27 * When a new header is added to either the top level folder, or to the
28 * corresponding internal subfolder, it should be added here. Headers
29 * added to the various subparts (e.g. matchers, generators, etc...),
30 * should go their respective catch-all headers.
31 */
32
33#ifndef CATCH_ALL_HPP_INCLUDED
34#define CATCH_ALL_HPP_INCLUDED
35
36
37
38/** \file
39 * This is a convenience header for Catch2's benchmarking. It includes
40 * **all** of Catch2 headers related to benchmarking.
41 *
42 * Generally the Catch2 users should use specific includes they need,
43 * but this header can be used instead for ease-of-experimentation, or
44 * just plain convenience, at the cost of (significantly) increased
45 * compilation times.
46 *
47 * When a new header is added to either the `benchmark` folder, or to
48 * the corresponding internal (detail) subfolder, it should be added here.
49 */
50
51#ifndef CATCH_BENCHMARK_ALL_HPP_INCLUDED
52#define CATCH_BENCHMARK_ALL_HPP_INCLUDED
53
54
55
56// Adapted from donated nonius code.
57
58#ifndef CATCH_BENCHMARK_HPP_INCLUDED
59#define CATCH_BENCHMARK_HPP_INCLUDED
60
61
62
63#ifndef CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
64#define CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
65
66// Detect a number of compiler features - by compiler
67// The following features are defined:
68//
69// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported?
70// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported?
71// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled?
72// ****************
73// Note to maintainers: if new toggles are added please document them
74// in configuration.md, too
75// ****************
76
77// In general each macro has a _NO_<feature name> form
78// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature.
79// Many features, at point of detection, define an _INTERNAL_ macro, so they
80// can be combined, en-mass, with the _NO_ forms later.
81
82
83
84#ifndef CATCH_PLATFORM_HPP_INCLUDED
85#define CATCH_PLATFORM_HPP_INCLUDED
86
87// See e.g.:
88// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html
89#ifdef __APPLE__
90# ifndef __has_extension
91# define __has_extension(x) 0
92# endif
93# include <TargetConditionals.h>
94# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \
95 (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1)
96# define CATCH_PLATFORM_MAC
97# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1)
98# define CATCH_PLATFORM_IPHONE
99# endif
100
101#elif defined(linux) || defined(__linux) || defined(__linux__)
102# define CATCH_PLATFORM_LINUX
103
104#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__)
105# define CATCH_PLATFORM_WINDOWS
106
107# if defined( WINAPI_FAMILY ) && ( WINAPI_FAMILY == WINAPI_FAMILY_APP )
108# define CATCH_PLATFORM_WINDOWS_UWP
109# endif
110
111#elif defined(__ORBIS__) || defined(__PROSPERO__)
112# define CATCH_PLATFORM_PLAYSTATION
113
114#endif
115
116#endif // CATCH_PLATFORM_HPP_INCLUDED
117
118#ifdef __cplusplus
119
120# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
121# define CATCH_CPP17_OR_GREATER
122# endif
123
124# if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L)
125# define CATCH_CPP20_OR_GREATER
126# endif
127
128#endif
129
130// Only GCC compiler should be used in this block, so other compilers trying to
131// mask themselves as GCC should be ignored.
132#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) && !defined(__NVCOMPILER)
133# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" )
134# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" )
135
136// This only works on GCC 9+. so we have to also add a global suppression of Wparentheses
137// for older versions of GCC.
138# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
139 _Pragma( "GCC diagnostic ignored \"-Wparentheses\"" )
140
141# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
142 _Pragma( "GCC diagnostic ignored \"-Wunused-result\"" )
143
144# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
145 _Pragma( "GCC diagnostic ignored \"-Wunused-variable\"" )
146
147# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
148 _Pragma( "GCC diagnostic ignored \"-Wuseless-cast\"" )
149
150# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
151 _Pragma( "GCC diagnostic ignored \"-Wshadow\"" )
152
153# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__)
154
155#endif
156
157#if defined(__NVCOMPILER)
158# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "diag push" )
159# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "diag pop" )
160# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress declared_but_not_referenced" )
161#endif
162
163#if defined(__CUDACC__) && !defined(__clang__)
164# ifdef __NVCC_DIAG_PRAGMA_SUPPORT__
165// New pragmas introduced in CUDA 11.5+
166# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic push" )
167# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "nv_diagnostic pop" )
168# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "nv_diag_suppress 177" )
169# else
170# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS _Pragma( "diag_suppress 177" )
171# endif
172#endif
173
174// clang-cl defines _MSC_VER as well as __clang__, which could cause the
175// start/stop internal suppression macros to be double defined.
176#if defined(__clang__) && !defined(_MSC_VER)
177
178# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" )
179# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" )
180
181#endif // __clang__ && !_MSC_VER
182
183#if defined(__clang__)
184
185// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug
186// which results in calls to destructors being emitted for each temporary,
187// without a matching initialization. In practice, this can result in something
188// like `std::string::~string` being called on an uninitialized value.
189//
190// For example, this code will likely segfault under IBM XL:
191// ```
192// REQUIRE(std::string("12") + "34" == "1234")
193// ```
194//
195// Similarly, NVHPC's implementation of `__builtin_constant_p` has a bug which
196// results in calls to the immediately evaluated lambda expressions to be
197// reported as unevaluated lambdas.
198// https://developer.nvidia.com/nvidia_bug/3321845.
199//
200// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented.
201# if !defined(__ibmxl__) && !defined(__CUDACC__) && !defined( __NVCOMPILER )
202# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */
203# endif
204
205
206# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
207 _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \
208 _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"")
209
210# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
211 _Pragma( "clang diagnostic ignored \"-Wparentheses\"" )
212
213# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
214 _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" )
215
216# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
217 _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" )
218
219# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
220 _Pragma( "clang diagnostic ignored \"-Wunused-template\"" )
221
222# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
223 _Pragma( "clang diagnostic ignored \"-Wcomma\"" )
224
225# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
226 _Pragma( "clang diagnostic ignored \"-Wshadow\"" )
227
228#endif // __clang__
229
230
231////////////////////////////////////////////////////////////////////////////////
232// We know some environments not to support full POSIX signals
233#if defined( CATCH_PLATFORM_WINDOWS ) || \
234 defined( CATCH_PLATFORM_PLAYSTATION ) || \
235 defined( __CYGWIN__ ) || \
236 defined( __QNX__ ) || \
237 defined( __EMSCRIPTEN__ ) || \
238 defined( __DJGPP__ ) || \
239 defined( __OS400__ )
240# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS
241#else
242# define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS
243#endif
244
245////////////////////////////////////////////////////////////////////////////////
246// Assume that some platforms do not support getenv.
247#if defined( CATCH_PLATFORM_WINDOWS_UWP ) || \
248 defined( CATCH_PLATFORM_PLAYSTATION ) || \
249 defined( _GAMING_XBOX )
250# define CATCH_INTERNAL_CONFIG_NO_GETENV
251#else
252# define CATCH_INTERNAL_CONFIG_GETENV
253#endif
254
255////////////////////////////////////////////////////////////////////////////////
256// Android somehow still does not support std::to_string
257#if defined(__ANDROID__)
258# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
259#endif
260
261////////////////////////////////////////////////////////////////////////////////
262// Not all Windows environments support SEH properly
263#if defined(__MINGW32__)
264# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
265#endif
266
267////////////////////////////////////////////////////////////////////////////////
268// PS4
269#if defined(__ORBIS__)
270# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE
271#endif
272
273////////////////////////////////////////////////////////////////////////////////
274// Cygwin
275#ifdef __CYGWIN__
276
277// Required for some versions of Cygwin to declare gettimeofday
278// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin
279# define _BSD_SOURCE
280// some versions of cygwin (most) do not support std::to_string. Use the libstd check.
281// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813
282# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \
283 && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF))
284
285# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING
286
287# endif
288#endif // __CYGWIN__
289
290////////////////////////////////////////////////////////////////////////////////
291// Visual C++
292#if defined(_MSC_VER)
293
294// We want to defer to nvcc-specific warning suppression if we are compiled
295// with nvcc masquerading for MSVC.
296# if !defined( __CUDACC__ )
297# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
298 __pragma( warning( push ) )
299# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
300 __pragma( warning( pop ) )
301# endif
302
303// Universal Windows platform does not support SEH
304// Or console colours (or console at all...)
305# if defined(CATCH_PLATFORM_WINDOWS_UWP)
306# define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
307# else
308# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH
309# endif
310
311// MSVC traditional preprocessor needs some workaround for __VA_ARGS__
312// _MSVC_TRADITIONAL == 0 means new conformant preprocessor
313// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor
314# if !defined(__clang__) // Handle Clang masquerading for msvc
315# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL)
316# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
317# endif // MSVC_TRADITIONAL
318# endif // __clang__
319
320#endif // _MSC_VER
321
322#if defined(_REENTRANT) || defined(_MSC_VER)
323// Enable async processing, as -pthread is specified or no additional linking is required
324# define CATCH_INTERNAL_CONFIG_USE_ASYNC
325#endif // _MSC_VER
326
327////////////////////////////////////////////////////////////////////////////////
328// Check if we are compiled with -fno-exceptions or equivalent
329#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND)
330# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED
331#endif
332
333
334////////////////////////////////////////////////////////////////////////////////
335// Embarcadero C++Build
336#if defined(__BORLANDC__)
337 #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN
338#endif
339
340////////////////////////////////////////////////////////////////////////////////
341
342// RTX is a special version of Windows that is real time.
343// This means that it is detected as Windows, but does not provide
344// the same set of capabilities as real Windows does.
345#if defined(UNDER_RTSS) || defined(RTX64_BUILD)
346 #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH
347 #define CATCH_INTERNAL_CONFIG_NO_ASYNC
348 #define CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32
349#endif
350
351#if !defined(_GLIBCXX_USE_C99_MATH_TR1)
352#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER
353#endif
354
355// Various stdlib support checks that require __has_include
356#if defined(__has_include)
357 // Check if string_view is available and usable
358 #if __has_include(<string_view>) && defined(CATCH_CPP17_OR_GREATER)
359 # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW
360 #endif
361
362 // Check if optional is available and usable
363 # if __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
364 # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL
365 # endif // __has_include(<optional>) && defined(CATCH_CPP17_OR_GREATER)
366
367 // Check if byte is available and usable
368 # if __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
369 # include <cstddef>
370 # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0)
371 # define CATCH_INTERNAL_CONFIG_CPP17_BYTE
372 # endif
373 # endif // __has_include(<cstddef>) && defined(CATCH_CPP17_OR_GREATER)
374
375 // Check if variant is available and usable
376 # if __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
377 # if defined(__clang__) && (__clang_major__ < 8)
378 // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852
379 // fix should be in clang 8, workaround in libstdc++ 8.2
380 # include <ciso646>
381 # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
382 # define CATCH_CONFIG_NO_CPP17_VARIANT
383 # else
384 # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
385 # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9)
386 # else
387 # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT
388 # endif // defined(__clang__) && (__clang_major__ < 8)
389 # endif // __has_include(<variant>) && defined(CATCH_CPP17_OR_GREATER)
390#endif // defined(__has_include)
391
392
393#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH)
394# define CATCH_CONFIG_WINDOWS_SEH
395#endif
396// This is set by default, because we assume that unix compilers are posix-signal-compatible by default.
397#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS)
398# define CATCH_CONFIG_POSIX_SIGNALS
399#endif
400
401#if defined(CATCH_INTERNAL_CONFIG_GETENV) && !defined(CATCH_INTERNAL_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_NO_GETENV) && !defined(CATCH_CONFIG_GETENV)
402# define CATCH_CONFIG_GETENV
403#endif
404
405#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING)
406# define CATCH_CONFIG_CPP11_TO_STRING
407#endif
408
409#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL)
410# define CATCH_CONFIG_CPP17_OPTIONAL
411#endif
412
413#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW)
414# define CATCH_CONFIG_CPP17_STRING_VIEW
415#endif
416
417#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT)
418# define CATCH_CONFIG_CPP17_VARIANT
419#endif
420
421#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE)
422# define CATCH_CONFIG_CPP17_BYTE
423#endif
424
425
426#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT)
427# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE
428#endif
429
430#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE)
431# define CATCH_CONFIG_NEW_CAPTURE
432#endif
433
434#if !defined( CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED ) && \
435 !defined( CATCH_CONFIG_DISABLE_EXCEPTIONS ) && \
436 !defined( CATCH_CONFIG_NO_DISABLE_EXCEPTIONS )
437# define CATCH_CONFIG_DISABLE_EXCEPTIONS
438#endif
439
440#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN)
441# define CATCH_CONFIG_POLYFILL_ISNAN
442#endif
443
444#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC)
445# define CATCH_CONFIG_USE_ASYNC
446#endif
447
448#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER)
449# define CATCH_CONFIG_GLOBAL_NEXTAFTER
450#endif
451
452
453// Even if we do not think the compiler has that warning, we still have
454// to provide a macro that can be used by the code.
455#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION)
456# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION
457#endif
458#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION)
459# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
460#endif
461#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS)
462# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS
463#endif
464#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS)
465# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS
466#endif
467#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT)
468# define CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT
469#endif
470#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS)
471# define CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS
472#endif
473#if !defined(CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS)
474# define CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS
475#endif
476#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS)
477# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS
478#endif
479#if !defined( CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS )
480# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
481#endif
482#if !defined( CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS )
483# define CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS
484#endif
485#if !defined( CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS )
486# define CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS
487#endif
488
489
490// The goal of this macro is to avoid evaluation of the arguments, but
491// still have the compiler warn on problems inside...
492#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN)
493# define CATCH_INTERNAL_IGNORE_BUT_WARN(...)
494#endif
495
496#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10)
497# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
498#elif defined(__clang__) && (__clang_major__ < 5)
499# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS
500#endif
501
502
503#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
504#define CATCH_TRY if ((true))
505#define CATCH_CATCH_ALL if ((false))
506#define CATCH_CATCH_ANON(type) if ((false))
507#else
508#define CATCH_TRY try
509#define CATCH_CATCH_ALL catch (...)
510#define CATCH_CATCH_ANON(type) catch (type)
511#endif
512
513#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR)
514#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
515#endif
516
517#if defined( CATCH_PLATFORM_WINDOWS ) && \
518 !defined( CATCH_CONFIG_COLOUR_WIN32 ) && \
519 !defined( CATCH_CONFIG_NO_COLOUR_WIN32 ) && \
520 !defined( CATCH_INTERNAL_CONFIG_NO_COLOUR_WIN32 )
521# define CATCH_CONFIG_COLOUR_WIN32
522#endif
523
524#if defined( CATCH_CONFIG_SHARED_LIBRARY ) && defined( _MSC_VER ) && \
525 !defined( CATCH_CONFIG_STATIC )
526# ifdef Catch2_EXPORTS
527# define CATCH_EXPORT //__declspec( dllexport ) // not needed
528# else
529# define CATCH_EXPORT __declspec( dllimport )
530# endif
531#else
532# define CATCH_EXPORT
533#endif
534
535#endif // CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
536
537
538#ifndef CATCH_CONTEXT_HPP_INCLUDED
539#define CATCH_CONTEXT_HPP_INCLUDED
540
541
542namespace Catch {
543
544 class IResultCapture;
545 class IConfig;
546
547 class Context {
548 IConfig const* m_config = nullptr;
549 IResultCapture* m_resultCapture = nullptr;
550
551 CATCH_EXPORT static Context* currentContext;
552 friend Context& getCurrentMutableContext();
553 friend Context const& getCurrentContext();
554 static void createContext();
555 friend void cleanUpContext();
556
557 public:
558 constexpr IResultCapture* getResultCapture() const {
559 return m_resultCapture;
560 }
561 constexpr IConfig const* getConfig() const { return m_config; }
562 constexpr void setResultCapture( IResultCapture* resultCapture ) {
563 m_resultCapture = resultCapture;
564 }
565 constexpr void setConfig( IConfig const* config ) { m_config = config; }
566
567 };
568
569 Context& getCurrentMutableContext();
570
571 inline Context const& getCurrentContext() {
572 // We duplicate the logic from `getCurrentMutableContext` here,
573 // to avoid paying the call overhead in debug mode.
574 if ( !Context::currentContext ) { Context::createContext(); }
575 // NOLINTNEXTLINE(clang-analyzer-core.uninitialized.UndefReturn)
576 return *Context::currentContext;
577 }
578
579 void cleanUpContext();
580
581 class SimplePcg32;
582 SimplePcg32& sharedRng();
583}
584
585#endif // CATCH_CONTEXT_HPP_INCLUDED
586
587
588#ifndef CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
589#define CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
590
591#include <type_traits>
592
593//! Replacement for std::move with better compile time performance
594#define CATCH_MOVE(...) static_cast<std::remove_reference_t<decltype(__VA_ARGS__)>&&>(__VA_ARGS__)
595
596//! Replacement for std::forward with better compile time performance
597#define CATCH_FORWARD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
598
599#endif // CATCH_MOVE_AND_FORWARD_HPP_INCLUDED
600
601
602#ifndef CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
603#define CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
604
605namespace Catch {
606
607 //! Used to signal that an assertion macro failed
608 struct TestFailureException{};
609 //! Used to signal that the remainder of a test should be skipped
610 struct TestSkipException {};
611
612 /**
613 * Outlines throwing of `TestFailureException` into a single TU
614 *
615 * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
616 */
617 [[noreturn]] void throw_test_failure_exception();
618
619 /**
620 * Outlines throwing of `TestSkipException` into a single TU
621 *
622 * Also handles `CATCH_CONFIG_DISABLE_EXCEPTIONS` for callers.
623 */
624 [[noreturn]] void throw_test_skip_exception();
625
626} // namespace Catch
627
628#endif // CATCH_TEST_FAILURE_EXCEPTION_HPP_INCLUDED
629
630
631#ifndef CATCH_UNIQUE_NAME_HPP_INCLUDED
632#define CATCH_UNIQUE_NAME_HPP_INCLUDED
633
634
635
636
637/** \file
638 * Wrapper for the CONFIG configuration option
639 *
640 * When generating internal unique names, there are two options. Either
641 * we mix in the current line number, or mix in an incrementing number.
642 * We prefer the latter, using `__COUNTER__`, but users might want to
643 * use the former.
644 */
645
646#ifndef CATCH_CONFIG_COUNTER_HPP_INCLUDED
647#define CATCH_CONFIG_COUNTER_HPP_INCLUDED
648
649
650#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L )
651 #define CATCH_INTERNAL_CONFIG_COUNTER
652#endif
653
654#if defined( CATCH_INTERNAL_CONFIG_COUNTER ) && \
655 !defined( CATCH_CONFIG_NO_COUNTER ) && \
656 !defined( CATCH_CONFIG_COUNTER )
657# define CATCH_CONFIG_COUNTER
658#endif
659
660
661#endif // CATCH_CONFIG_COUNTER_HPP_INCLUDED
662#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
663#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
664#ifdef CATCH_CONFIG_COUNTER
665# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ )
666#else
667# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
668#endif
669
670#endif // CATCH_UNIQUE_NAME_HPP_INCLUDED
671
672
673#ifndef CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
674#define CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
675
676#include <string>
677
678
679
680#ifndef CATCH_STRINGREF_HPP_INCLUDED
681#define CATCH_STRINGREF_HPP_INCLUDED
682
683#include <cstddef>
684#include <string>
685#include <iosfwd>
686#include <cassert>
687
688#include <cstring>
689
690namespace Catch {
691
692 /// A non-owning string class (similar to the forthcoming std::string_view)
693 /// Note that, because a StringRef may be a substring of another string,
694 /// it may not be null terminated.
695 class StringRef {
696 public:
697 using size_type = std::size_t;
698 using const_iterator = const char*;
699
700 static constexpr size_type npos{ static_cast<size_type>( -1 ) };
701
702 private:
703 static constexpr char const* const s_empty = "";
704
705 char const* m_start = s_empty;
706 size_type m_size = 0;
707
708 public: // construction
709 constexpr StringRef() noexcept = default;
710
711 StringRef( char const* rawChars ) noexcept;
712
713 constexpr StringRef( char const* rawChars, size_type size ) noexcept
714 : m_start( rawChars ),
715 m_size( size )
716 {}
717
718 StringRef( std::string const& stdString ) noexcept
719 : m_start( stdString.c_str() ),
720 m_size( stdString.size() )
721 {}
722
723 explicit operator std::string() const {
724 return std::string(m_start, m_size);
725 }
726
727 public: // operators
728 auto operator == ( StringRef other ) const noexcept -> bool {
729 return m_size == other.m_size
730 && (std::memcmp( m_start, other.m_start, m_size ) == 0);
731 }
732 auto operator != (StringRef other) const noexcept -> bool {
733 return !(*this == other);
734 }
735
736 constexpr auto operator[] ( size_type index ) const noexcept -> char {
737 assert(index < m_size);
738 return m_start[index];
739 }
740
741 bool operator<(StringRef rhs) const noexcept;
742
743 public: // named queries
744 constexpr auto empty() const noexcept -> bool {
745 return m_size == 0;
746 }
747 constexpr auto size() const noexcept -> size_type {
748 return m_size;
749 }
750
751 // Returns a substring of [start, start + length).
752 // If start + length > size(), then the substring is [start, size()).
753 // If start > size(), then the substring is empty.
754 constexpr StringRef substr(size_type start, size_type length) const noexcept {
755 if (start < m_size) {
756 const auto shortened_size = m_size - start;
757 return StringRef(m_start + start, (shortened_size < length) ? shortened_size : length);
758 } else {
759 return StringRef();
760 }
761 }
762
763 // Returns the current start pointer. May not be null-terminated.
764 constexpr char const* data() const noexcept {
765 return m_start;
766 }
767
768 constexpr const_iterator begin() const { return m_start; }
769 constexpr const_iterator end() const { return m_start + m_size; }
770
771
772 friend std::string& operator += (std::string& lhs, StringRef rhs);
773 friend std::ostream& operator << (std::ostream& os, StringRef str);
774 friend std::string operator+(StringRef lhs, StringRef rhs);
775
776 /**
777 * Provides a three-way comparison with rhs
778 *
779 * Returns negative number if lhs < rhs, 0 if lhs == rhs, and a positive
780 * number if lhs > rhs
781 */
782 int compare( StringRef rhs ) const;
783 };
784
785
786 constexpr auto operator ""_sr( char const* rawChars, std::size_t size ) noexcept -> StringRef {
787 return StringRef( rawChars, size );
788 }
789} // namespace Catch
790
791constexpr auto operator ""_catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef {
792 return Catch::StringRef( rawChars, size );
793}
794
795#endif // CATCH_STRINGREF_HPP_INCLUDED
796
797
798#ifndef CATCH_RESULT_TYPE_HPP_INCLUDED
799#define CATCH_RESULT_TYPE_HPP_INCLUDED
800
801namespace Catch {
802
803 // ResultWas::OfType enum
804 struct ResultWas { enum OfType {
805 Unknown = -1,
806 Ok = 0,
807 Info = 1,
808 Warning = 2,
809 // TODO: Should explicit skip be considered "not OK" (cf. isOk)? I.e., should it have the failure bit?
810 ExplicitSkip = 4,
811
812 FailureBit = 0x10,
813
814 ExpressionFailed = FailureBit | 1,
815 ExplicitFailure = FailureBit | 2,
816
817 Exception = 0x100 | FailureBit,
818
819 ThrewException = Exception | 1,
820 DidntThrowException = Exception | 2,
821
822 FatalErrorCondition = 0x200 | FailureBit
823
824 }; };
825
826 constexpr bool isOk( ResultWas::OfType resultType ) {
827 return ( resultType & ResultWas::FailureBit ) == 0;
828 }
829 constexpr bool isJustInfo( int flags ) { return flags == ResultWas::Info; }
830
831
832 // ResultDisposition::Flags enum
833 struct ResultDisposition { enum Flags {
834 Normal = 0x01,
835
836 ContinueOnFailure = 0x02, // Failures fail test, but execution continues
837 FalseTest = 0x04, // Prefix expression with !
838 SuppressFail = 0x08 // Failures are reported but do not fail the test
839 }; };
840
841 constexpr ResultDisposition::Flags operator|( ResultDisposition::Flags lhs,
842 ResultDisposition::Flags rhs ) {
843 return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) |
844 static_cast<int>( rhs ) );
845 }
846
847 constexpr bool isFalseTest( int flags ) {
848 return ( flags & ResultDisposition::FalseTest ) != 0;
849 }
850 constexpr bool shouldSuppressFailure( int flags ) {
851 return ( flags & ResultDisposition::SuppressFail ) != 0;
852 }
853
854} // end namespace Catch
855
856#endif // CATCH_RESULT_TYPE_HPP_INCLUDED
857
858
859#ifndef CATCH_UNIQUE_PTR_HPP_INCLUDED
860#define CATCH_UNIQUE_PTR_HPP_INCLUDED
861
862#include <cassert>
863#include <type_traits>
864
865
866namespace Catch {
867namespace Detail {
868 /**
869 * A reimplementation of `std::unique_ptr` for improved compilation performance
870 *
871 * Does not support arrays nor custom deleters.
872 */
873 template <typename T>
874 class unique_ptr {
875 T* m_ptr;
876 public:
877 constexpr unique_ptr(std::nullptr_t = nullptr):
878 m_ptr{}
879 {}
880 explicit constexpr unique_ptr(T* ptr):
881 m_ptr(ptr)
882 {}
883
884 template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
885 unique_ptr(unique_ptr<U>&& from):
886 m_ptr(from.release())
887 {}
888
889 template <typename U, typename = std::enable_if_t<std::is_base_of<T, U>::value>>
890 unique_ptr& operator=(unique_ptr<U>&& from) {
891 reset(from.release());
892
893 return *this;
894 }
895
896 unique_ptr(unique_ptr const&) = delete;
897 unique_ptr& operator=(unique_ptr const&) = delete;
898
899 unique_ptr(unique_ptr&& rhs) noexcept:
900 m_ptr(rhs.m_ptr) {
901 rhs.m_ptr = nullptr;
902 }
903 unique_ptr& operator=(unique_ptr&& rhs) noexcept {
904 reset(rhs.release());
905
906 return *this;
907 }
908
909 ~unique_ptr() {
910 delete m_ptr;
911 }
912
913 T& operator*() {
914 assert(m_ptr);
915 return *m_ptr;
916 }
917 T const& operator*() const {
918 assert(m_ptr);
919 return *m_ptr;
920 }
921 T* operator->() noexcept {
922 assert(m_ptr);
923 return m_ptr;
924 }
925 T const* operator->() const noexcept {
926 assert(m_ptr);
927 return m_ptr;
928 }
929
930 T* get() { return m_ptr; }
931 T const* get() const { return m_ptr; }
932
933 void reset(T* ptr = nullptr) {
934 delete m_ptr;
935 m_ptr = ptr;
936 }
937
938 T* release() {
939 auto temp = m_ptr;
940 m_ptr = nullptr;
941 return temp;
942 }
943
944 explicit operator bool() const {
945 return m_ptr;
946 }
947
948 friend void swap(unique_ptr& lhs, unique_ptr& rhs) {
949 auto temp = lhs.m_ptr;
950 lhs.m_ptr = rhs.m_ptr;
951 rhs.m_ptr = temp;
952 }
953 };
954
955 //! Specialization to cause compile-time error for arrays
956 template <typename T>
957 class unique_ptr<T[]>;
958
959 template <typename T, typename... Args>
960 unique_ptr<T> make_unique(Args&&... args) {
961 return unique_ptr<T>(new T(CATCH_FORWARD(args)...));
962 }
963
964
965} // end namespace Detail
966} // end namespace Catch
967
968#endif // CATCH_UNIQUE_PTR_HPP_INCLUDED
969
970
971#ifndef CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
972#define CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
973
974
975
976// Adapted from donated nonius code.
977
978#ifndef CATCH_CLOCK_HPP_INCLUDED
979#define CATCH_CLOCK_HPP_INCLUDED
980
981#include <chrono>
982
983namespace Catch {
984 namespace Benchmark {
985 using IDuration = std::chrono::nanoseconds;
986 using FDuration = std::chrono::duration<double, std::nano>;
987
988 template <typename Clock>
989 using TimePoint = typename Clock::time_point;
990
991 using default_clock = std::chrono::steady_clock;
992 } // namespace Benchmark
993} // namespace Catch
994
995#endif // CATCH_CLOCK_HPP_INCLUDED
996
997namespace Catch {
998
999 // We cannot forward declare the type with default template argument
1000 // multiple times, so it is split out into a separate header so that
1001 // we can prevent multiple declarations in dependees
1002 template <typename Duration = Benchmark::FDuration>
1003 struct BenchmarkStats;
1004
1005} // end namespace Catch
1006
1007#endif // CATCH_BENCHMARK_STATS_FWD_HPP_INCLUDED
1008
1009namespace Catch {
1010
1011 class AssertionResult;
1012 struct AssertionInfo;
1013 struct SectionInfo;
1014 struct SectionEndInfo;
1015 struct MessageInfo;
1016 struct MessageBuilder;
1017 struct Counts;
1018 struct AssertionReaction;
1019 struct SourceLineInfo;
1020
1021 class ITransientExpression;
1022 class IGeneratorTracker;
1023
1024 struct BenchmarkInfo;
1025
1026 namespace Generators {
1027 class GeneratorUntypedBase;
1028 using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
1029 }
1030
1031
1032 class IResultCapture {
1033 public:
1034 virtual ~IResultCapture();
1035
1036 virtual void notifyAssertionStarted( AssertionInfo const& info ) = 0;
1037 virtual bool sectionStarted( StringRef sectionName,
1038 SourceLineInfo const& sectionLineInfo,
1039 Counts& assertions ) = 0;
1040 virtual void sectionEnded( SectionEndInfo&& endInfo ) = 0;
1041 virtual void sectionEndedEarly( SectionEndInfo&& endInfo ) = 0;
1042
1043 virtual IGeneratorTracker*
1044 acquireGeneratorTracker( StringRef generatorName,
1045 SourceLineInfo const& lineInfo ) = 0;
1046 virtual IGeneratorTracker*
1047 createGeneratorTracker( StringRef generatorName,
1048 SourceLineInfo lineInfo,
1049 Generators::GeneratorBasePtr&& generator ) = 0;
1050
1051 virtual void benchmarkPreparing( StringRef name ) = 0;
1052 virtual void benchmarkStarting( BenchmarkInfo const& info ) = 0;
1053 virtual void benchmarkEnded( BenchmarkStats<> const& stats ) = 0;
1054 virtual void benchmarkFailed( StringRef error ) = 0;
1055
1056 virtual void pushScopedMessage( MessageInfo const& message ) = 0;
1057 virtual void popScopedMessage( MessageInfo const& message ) = 0;
1058
1059 virtual void emplaceUnscopedMessage( MessageBuilder&& builder ) = 0;
1060
1061 virtual void handleFatalErrorCondition( StringRef message ) = 0;
1062
1063 virtual void handleExpr
1064 ( AssertionInfo const& info,
1065 ITransientExpression const& expr,
1066 AssertionReaction& reaction ) = 0;
1067 virtual void handleMessage
1068 ( AssertionInfo const& info,
1069 ResultWas::OfType resultType,
1070 std::string&& message,
1071 AssertionReaction& reaction ) = 0;
1072 virtual void handleUnexpectedExceptionNotThrown
1073 ( AssertionInfo const& info,
1074 AssertionReaction& reaction ) = 0;
1075 virtual void handleUnexpectedInflightException
1076 ( AssertionInfo const& info,
1077 std::string&& message,
1078 AssertionReaction& reaction ) = 0;
1079 virtual void handleIncomplete
1080 ( AssertionInfo const& info ) = 0;
1081 virtual void handleNonExpr
1082 ( AssertionInfo const &info,
1083 ResultWas::OfType resultType,
1084 AssertionReaction &reaction ) = 0;
1085
1086
1087
1088 virtual bool lastAssertionPassed() = 0;
1089 virtual void assertionPassed() = 0;
1090
1091 // Deprecated, do not use:
1092 virtual std::string getCurrentTestName() const = 0;
1093 virtual const AssertionResult* getLastResult() const = 0;
1094 virtual void exceptionEarlyReported() = 0;
1095 };
1096
1097 IResultCapture& getResultCapture();
1098}
1099
1100#endif // CATCH_INTERFACES_CAPTURE_HPP_INCLUDED
1101
1102
1103#ifndef CATCH_INTERFACES_CONFIG_HPP_INCLUDED
1104#define CATCH_INTERFACES_CONFIG_HPP_INCLUDED
1105
1106
1107
1108#ifndef CATCH_NONCOPYABLE_HPP_INCLUDED
1109#define CATCH_NONCOPYABLE_HPP_INCLUDED
1110
1111namespace Catch {
1112 namespace Detail {
1113
1114 //! Deriving classes become noncopyable and nonmovable
1115 class NonCopyable {
1116 NonCopyable( NonCopyable const& ) = delete;
1117 NonCopyable( NonCopyable&& ) = delete;
1118 NonCopyable& operator=( NonCopyable const& ) = delete;
1119 NonCopyable& operator=( NonCopyable&& ) = delete;
1120
1121 protected:
1122 NonCopyable() noexcept = default;
1123 };
1124
1125 } // namespace Detail
1126} // namespace Catch
1127
1128#endif // CATCH_NONCOPYABLE_HPP_INCLUDED
1129
1130#include <chrono>
1131#include <iosfwd>
1132#include <string>
1133#include <vector>
1134
1135namespace Catch {
1136
1137 enum class Verbosity {
1138 Quiet = 0,
1139 Normal,
1140 High
1141 };
1142
1143 struct WarnAbout { enum What {
1144 Nothing = 0x00,
1145 //! A test case or leaf section did not run any assertions
1146 NoAssertions = 0x01,
1147 //! A command line test spec matched no test cases
1148 UnmatchedTestSpec = 0x02,
1149 }; };
1150
1151 enum class ShowDurations {
1152 DefaultForReporter,
1153 Always,
1154 Never
1155 };
1156 enum class TestRunOrder {
1157 Declared,
1158 LexicographicallySorted,
1159 Randomized
1160 };
1161 enum class ColourMode : std::uint8_t {
1162 //! Let Catch2 pick implementation based on platform detection
1163 PlatformDefault,
1164 //! Use ANSI colour code escapes
1165 ANSI,
1166 //! Use Win32 console colour API
1167 Win32,
1168 //! Don't use any colour
1169 None
1170 };
1171 struct WaitForKeypress { enum When {
1172 Never,
1173 BeforeStart = 1,
1174 BeforeExit = 2,
1175 BeforeStartAndExit = BeforeStart | BeforeExit
1176 }; };
1177
1178 class TestSpec;
1179 class IStream;
1180
1181 class IConfig : public Detail::NonCopyable {
1182 public:
1183 virtual ~IConfig();
1184
1185 virtual bool allowThrows() const = 0;
1186 virtual StringRef name() const = 0;
1187 virtual bool includeSuccessfulResults() const = 0;
1188 virtual bool shouldDebugBreak() const = 0;
1189 virtual bool warnAboutMissingAssertions() const = 0;
1190 virtual bool warnAboutUnmatchedTestSpecs() const = 0;
1191 virtual bool zeroTestsCountAsSuccess() const = 0;
1192 virtual int abortAfter() const = 0;
1193 virtual bool showInvisibles() const = 0;
1194 virtual ShowDurations showDurations() const = 0;
1195 virtual double minDuration() const = 0;
1196 virtual TestSpec const& testSpec() const = 0;
1197 virtual bool hasTestFilters() const = 0;
1198 virtual std::vector<std::string> const& getTestsOrTags() const = 0;
1199 virtual TestRunOrder runOrder() const = 0;
1200 virtual uint32_t rngSeed() const = 0;
1201 virtual unsigned int shardCount() const = 0;
1202 virtual unsigned int shardIndex() const = 0;
1203 virtual ColourMode defaultColourMode() const = 0;
1204 virtual std::vector<std::string> const& getSectionsToRun() const = 0;
1205 virtual Verbosity verbosity() const = 0;
1206
1207 virtual bool skipBenchmarks() const = 0;
1208 virtual bool benchmarkNoAnalysis() const = 0;
1209 virtual unsigned int benchmarkSamples() const = 0;
1210 virtual double benchmarkConfidenceInterval() const = 0;
1211 virtual unsigned int benchmarkResamples() const = 0;
1212 virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0;
1213 };
1214}
1215
1216#endif // CATCH_INTERFACES_CONFIG_HPP_INCLUDED
1217
1218
1219#ifndef CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
1220#define CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
1221
1222
1223#include <string>
1224
1225namespace Catch {
1226
1227 class TestCaseHandle;
1228 struct TestCaseInfo;
1229 class ITestCaseRegistry;
1230 class IExceptionTranslatorRegistry;
1231 class IExceptionTranslator;
1232 class ReporterRegistry;
1233 class IReporterFactory;
1234 class ITagAliasRegistry;
1235 class ITestInvoker;
1236 class IMutableEnumValuesRegistry;
1237 struct SourceLineInfo;
1238
1239 class StartupExceptionRegistry;
1240 class EventListenerFactory;
1241
1242 using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
1243
1244 class IRegistryHub {
1245 public:
1246 virtual ~IRegistryHub(); // = default
1247
1248 virtual ReporterRegistry const& getReporterRegistry() const = 0;
1249 virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
1250 virtual ITagAliasRegistry const& getTagAliasRegistry() const = 0;
1251 virtual IExceptionTranslatorRegistry const& getExceptionTranslatorRegistry() const = 0;
1252
1253
1254 virtual StartupExceptionRegistry const& getStartupExceptionRegistry() const = 0;
1255 };
1256
1257 class IMutableRegistryHub {
1258 public:
1259 virtual ~IMutableRegistryHub(); // = default
1260 virtual void registerReporter( std::string const& name, IReporterFactoryPtr factory ) = 0;
1261 virtual void registerListener( Detail::unique_ptr<EventListenerFactory> factory ) = 0;
1262 virtual void registerTest(Detail::unique_ptr<TestCaseInfo>&& testInfo, Detail::unique_ptr<ITestInvoker>&& invoker) = 0;
1263 virtual void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator ) = 0;
1264 virtual void registerTagAlias( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo ) = 0;
1265 virtual void registerStartupException() noexcept = 0;
1266 virtual IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() = 0;
1267 };
1268
1269 IRegistryHub const& getRegistryHub();
1270 IMutableRegistryHub& getMutableRegistryHub();
1271 void cleanUp();
1272 std::string translateActiveException();
1273
1274}
1275
1276#endif // CATCH_INTERFACES_REGISTRY_HUB_HPP_INCLUDED
1277
1278
1279#ifndef CATCH_BENCHMARK_STATS_HPP_INCLUDED
1280#define CATCH_BENCHMARK_STATS_HPP_INCLUDED
1281
1282
1283
1284// Adapted from donated nonius code.
1285
1286#ifndef CATCH_ESTIMATE_HPP_INCLUDED
1287#define CATCH_ESTIMATE_HPP_INCLUDED
1288
1289namespace Catch {
1290 namespace Benchmark {
1291 template <typename Type>
1292 struct Estimate {
1293 Type point;
1294 Type lower_bound;
1295 Type upper_bound;
1296 double confidence_interval;
1297 };
1298 } // namespace Benchmark
1299} // namespace Catch
1300
1301#endif // CATCH_ESTIMATE_HPP_INCLUDED
1302
1303
1304// Adapted from donated nonius code.
1305
1306#ifndef CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
1307#define CATCH_OUTLIER_CLASSIFICATION_HPP_INCLUDED
1308
1309namespace Catch {
1310 namespace Benchmark {
1311 struct OutlierClassification {
1312 int samples_seen = 0;
1313 int low_severe = 0; // more than 3 times IQR below Q1
1314 int low_mild = 0; // 1.5 to 3 times IQR below Q1
1315 int high_mild = 0; // 1.5 to 3 times IQR above Q3
1316 int high_severe = 0; // more than 3 times IQR above Q3
1317
1318 constexpr int total() const {
1319 return low_severe + low_mild + high_mild + high_severe;
1320 }
1321 };
1322 } // namespace Benchmark
1323} // namespace Catch
1324
1325#endif // CATCH_OUTLIERS_CLASSIFICATION_HPP_INCLUDED
1326// The fwd decl & default specialization needs to be seen by VS2017 before
1327// BenchmarkStats itself, or VS2017 will report compilation error.
1328
1329#include <string>
1330#include <vector>
1331
1332namespace Catch {
1333
1334 struct BenchmarkInfo {
1335 std::string name;
1336 double estimatedDuration;
1337 int iterations;
1338 unsigned int samples;
1339 unsigned int resamples;
1340 double clockResolution;
1341 double clockCost;
1342 };
1343
1344 // We need to keep template parameter for backwards compatibility,
1345 // but we also do not want to use the template paraneter.
1346 template <class Dummy>
1347 struct BenchmarkStats {
1348 BenchmarkInfo info;
1349
1350 std::vector<Benchmark::FDuration> samples;
1351 Benchmark::Estimate<Benchmark::FDuration> mean;
1352 Benchmark::Estimate<Benchmark::FDuration> standardDeviation;
1353 Benchmark::OutlierClassification outliers;
1354 double outlierVariance;
1355 };
1356
1357
1358} // end namespace Catch
1359
1360#endif // CATCH_BENCHMARK_STATS_HPP_INCLUDED
1361
1362
1363// Adapted from donated nonius code.
1364
1365#ifndef CATCH_ENVIRONMENT_HPP_INCLUDED
1366#define CATCH_ENVIRONMENT_HPP_INCLUDED
1367
1368
1369namespace Catch {
1370 namespace Benchmark {
1371 struct EnvironmentEstimate {
1372 FDuration mean;
1373 OutlierClassification outliers;
1374 };
1375 struct Environment {
1376 EnvironmentEstimate clock_resolution;
1377 EnvironmentEstimate clock_cost;
1378 };
1379 } // namespace Benchmark
1380} // namespace Catch
1381
1382#endif // CATCH_ENVIRONMENT_HPP_INCLUDED
1383
1384
1385// Adapted from donated nonius code.
1386
1387#ifndef CATCH_EXECUTION_PLAN_HPP_INCLUDED
1388#define CATCH_EXECUTION_PLAN_HPP_INCLUDED
1389
1390
1391
1392// Adapted from donated nonius code.
1393
1394#ifndef CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
1395#define CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
1396
1397
1398
1399// Adapted from donated nonius code.
1400
1401#ifndef CATCH_CHRONOMETER_HPP_INCLUDED
1402#define CATCH_CHRONOMETER_HPP_INCLUDED
1403
1404
1405
1406// Adapted from donated nonius code.
1407
1408#ifndef CATCH_OPTIMIZER_HPP_INCLUDED
1409#define CATCH_OPTIMIZER_HPP_INCLUDED
1410
1411#if defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
1412# include <atomic> // atomic_thread_fence
1413#endif
1414
1415
1416#include <type_traits>
1417
1418namespace Catch {
1419 namespace Benchmark {
1420#if defined(__GNUC__) || defined(__clang__)
1421 template <typename T>
1422 inline void keep_memory(T* p) {
1423 asm volatile("" : : "g"(p) : "memory");
1424 }
1425 inline void keep_memory() {
1426 asm volatile("" : : : "memory");
1427 }
1428
1429 namespace Detail {
1430 inline void optimizer_barrier() { keep_memory(); }
1431 } // namespace Detail
1432#elif defined(_MSC_VER) || defined(__IAR_SYSTEMS_ICC__)
1433
1434#if defined(_MSVC_VER)
1435#pragma optimize("", off)
1436#elif defined(__IAR_SYSTEMS_ICC__)
1437// For IAR the pragma only affects the following function
1438#pragma optimize=disable
1439#endif
1440 template <typename T>
1441 inline void keep_memory(T* p) {
1442 // thanks @milleniumbug
1443 *reinterpret_cast<char volatile*>(p) = *reinterpret_cast<char const volatile*>(p);
1444 }
1445 // TODO equivalent keep_memory()
1446#if defined(_MSVC_VER)
1447#pragma optimize("", on)
1448#endif
1449
1450 namespace Detail {
1451 inline void optimizer_barrier() {
1452 std::atomic_thread_fence(std::memory_order_seq_cst);
1453 }
1454 } // namespace Detail
1455
1456#endif
1457
1458 template <typename T>
1459 inline void deoptimize_value(T&& x) {
1460 keep_memory(&x);
1461 }
1462
1463 template <typename Fn, typename... Args>
1464 inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<!std::is_same<void, decltype(fn(args...))>::value> {
1465 deoptimize_value(CATCH_FORWARD(fn) (CATCH_FORWARD(args)...));
1466 }
1467
1468 template <typename Fn, typename... Args>
1469 inline auto invoke_deoptimized(Fn&& fn, Args&&... args) -> std::enable_if_t<std::is_same<void, decltype(fn(args...))>::value> {
1470 CATCH_FORWARD((fn)) (CATCH_FORWARD(args)...);
1471 }
1472 } // namespace Benchmark
1473} // namespace Catch
1474
1475#endif // CATCH_OPTIMIZER_HPP_INCLUDED
1476
1477
1478#ifndef CATCH_META_HPP_INCLUDED
1479#define CATCH_META_HPP_INCLUDED
1480
1481#include <type_traits>
1482
1483namespace Catch {
1484 template <typename>
1485 struct true_given : std::true_type {};
1486
1487 struct is_callable_tester {
1488 template <typename Fun, typename... Args>
1489 static true_given<decltype(std::declval<Fun>()(std::declval<Args>()...))> test(int);
1490 template <typename...>
1491 static std::false_type test(...);
1492 };
1493
1494 template <typename T>
1495 struct is_callable;
1496
1497 template <typename Fun, typename... Args>
1498 struct is_callable<Fun(Args...)> : decltype(is_callable_tester::test<Fun, Args...>(0)) {};
1499
1500
1501#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
1502 // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is
1503 // replaced with std::invoke_result here.
1504 template <typename Func, typename... U>
1505 using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::invoke_result_t<Func, U...>>>;
1506#else
1507 template <typename Func, typename... U>
1508 using FunctionReturnType = std::remove_reference_t<std::remove_cv_t<std::result_of_t<Func(U...)>>>;
1509#endif
1510
1511} // namespace Catch
1512
1513namespace mpl_{
1514 struct na;
1515}
1516
1517#endif // CATCH_META_HPP_INCLUDED
1518
1519namespace Catch {
1520 namespace Benchmark {
1521 namespace Detail {
1522 struct ChronometerConcept {
1523 virtual void start() = 0;
1524 virtual void finish() = 0;
1525 virtual ~ChronometerConcept(); // = default;
1526
1527 ChronometerConcept() = default;
1528 ChronometerConcept(ChronometerConcept const&) = default;
1529 ChronometerConcept& operator=(ChronometerConcept const&) = default;
1530 };
1531 template <typename Clock>
1532 struct ChronometerModel final : public ChronometerConcept {
1533 void start() override { started = Clock::now(); }
1534 void finish() override { finished = Clock::now(); }
1535
1536 IDuration elapsed() const {
1537 return std::chrono::duration_cast<std::chrono::nanoseconds>(
1538 finished - started );
1539 }
1540
1541 TimePoint<Clock> started;
1542 TimePoint<Clock> finished;
1543 };
1544 } // namespace Detail
1545
1546 struct Chronometer {
1547 public:
1548 template <typename Fun>
1549 void measure(Fun&& fun) { measure(CATCH_FORWARD(fun), is_callable<Fun(int)>()); }
1550
1551 int runs() const { return repeats; }
1552
1553 Chronometer(Detail::ChronometerConcept& meter, int repeats_)
1554 : impl(&meter)
1555 , repeats(repeats_) {}
1556
1557 private:
1558 template <typename Fun>
1559 void measure(Fun&& fun, std::false_type) {
1560 measure([&fun](int) { return fun(); }, std::true_type());
1561 }
1562
1563 template <typename Fun>
1564 void measure(Fun&& fun, std::true_type) {
1565 Detail::optimizer_barrier();
1566 impl->start();
1567 for (int i = 0; i < repeats; ++i) invoke_deoptimized(fun, i);
1568 impl->finish();
1569 Detail::optimizer_barrier();
1570 }
1571
1572 Detail::ChronometerConcept* impl;
1573 int repeats;
1574 };
1575 } // namespace Benchmark
1576} // namespace Catch
1577
1578#endif // CATCH_CHRONOMETER_HPP_INCLUDED
1579
1580#include <type_traits>
1581
1582namespace Catch {
1583 namespace Benchmark {
1584 namespace Detail {
1585 template <typename T, typename U>
1586 struct is_related
1587 : std::is_same<std::decay_t<T>, std::decay_t<U>> {};
1588
1589 /// We need to reinvent std::function because every piece of code that might add overhead
1590 /// in a measurement context needs to have consistent performance characteristics so that we
1591 /// can account for it in the measurement.
1592 /// Implementations of std::function with optimizations that aren't always applicable, like
1593 /// small buffer optimizations, are not uncommon.
1594 /// This is effectively an implementation of std::function without any such optimizations;
1595 /// it may be slow, but it is consistently slow.
1596 struct BenchmarkFunction {
1597 private:
1598 struct callable {
1599 virtual void call(Chronometer meter) const = 0;
1600 virtual ~callable(); // = default;
1601
1602 callable() = default;
1603 callable(callable&&) = default;
1604 callable& operator=(callable&&) = default;
1605 };
1606 template <typename Fun>
1607 struct model : public callable {
1608 model(Fun&& fun_) : fun(CATCH_MOVE(fun_)) {}
1609 model(Fun const& fun_) : fun(fun_) {}
1610
1611 void call(Chronometer meter) const override {
1612 call(meter, is_callable<Fun(Chronometer)>());
1613 }
1614 void call(Chronometer meter, std::true_type) const {
1615 fun(meter);
1616 }
1617 void call(Chronometer meter, std::false_type) const {
1618 meter.measure(fun);
1619 }
1620
1621 Fun fun;
1622 };
1623
1624 public:
1625 BenchmarkFunction();
1626
1627 template <typename Fun,
1628 std::enable_if_t<!is_related<Fun, BenchmarkFunction>::value, int> = 0>
1629 BenchmarkFunction(Fun&& fun)
1630 : f(new model<std::decay_t<Fun>>(CATCH_FORWARD(fun))) {}
1631
1632 BenchmarkFunction( BenchmarkFunction&& that ) noexcept:
1633 f( CATCH_MOVE( that.f ) ) {}
1634
1635 BenchmarkFunction&
1636 operator=( BenchmarkFunction&& that ) noexcept {
1637 f = CATCH_MOVE( that.f );
1638 return *this;
1639 }
1640
1641 void operator()(Chronometer meter) const { f->call(meter); }
1642
1643 private:
1644 Catch::Detail::unique_ptr<callable> f;
1645 };
1646 } // namespace Detail
1647 } // namespace Benchmark
1648} // namespace Catch
1649
1650#endif // CATCH_BENCHMARK_FUNCTION_HPP_INCLUDED
1651
1652
1653// Adapted from donated nonius code.
1654
1655#ifndef CATCH_REPEAT_HPP_INCLUDED
1656#define CATCH_REPEAT_HPP_INCLUDED
1657
1658#include <type_traits>
1659
1660namespace Catch {
1661 namespace Benchmark {
1662 namespace Detail {
1663 template <typename Fun>
1664 struct repeater {
1665 void operator()(int k) const {
1666 for (int i = 0; i < k; ++i) {
1667 fun();
1668 }
1669 }
1670 Fun fun;
1671 };
1672 template <typename Fun>
1673 repeater<std::decay_t<Fun>> repeat(Fun&& fun) {
1674 return { CATCH_FORWARD(fun) };
1675 }
1676 } // namespace Detail
1677 } // namespace Benchmark
1678} // namespace Catch
1679
1680#endif // CATCH_REPEAT_HPP_INCLUDED
1681
1682
1683// Adapted from donated nonius code.
1684
1685#ifndef CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
1686#define CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
1687
1688
1689
1690// Adapted from donated nonius code.
1691
1692#ifndef CATCH_MEASURE_HPP_INCLUDED
1693#define CATCH_MEASURE_HPP_INCLUDED
1694
1695
1696
1697// Adapted from donated nonius code.
1698
1699#ifndef CATCH_COMPLETE_INVOKE_HPP_INCLUDED
1700#define CATCH_COMPLETE_INVOKE_HPP_INCLUDED
1701
1702
1703namespace Catch {
1704 namespace Benchmark {
1705 namespace Detail {
1706 template <typename T>
1707 struct CompleteType { using type = T; };
1708 template <>
1709 struct CompleteType<void> { struct type {}; };
1710
1711 template <typename T>
1712 using CompleteType_t = typename CompleteType<T>::type;
1713
1714 template <typename Result>
1715 struct CompleteInvoker {
1716 template <typename Fun, typename... Args>
1717 static Result invoke(Fun&& fun, Args&&... args) {
1718 return CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
1719 }
1720 };
1721 template <>
1722 struct CompleteInvoker<void> {
1723 template <typename Fun, typename... Args>
1724 static CompleteType_t<void> invoke(Fun&& fun, Args&&... args) {
1725 CATCH_FORWARD(fun)(CATCH_FORWARD(args)...);
1726 return {};
1727 }
1728 };
1729
1730 // invoke and not return void :(
1731 template <typename Fun, typename... Args>
1732 CompleteType_t<FunctionReturnType<Fun, Args...>> complete_invoke(Fun&& fun, Args&&... args) {
1733 return CompleteInvoker<FunctionReturnType<Fun, Args...>>::invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
1734 }
1735
1736 } // namespace Detail
1737
1738 template <typename Fun>
1739 Detail::CompleteType_t<FunctionReturnType<Fun>> user_code(Fun&& fun) {
1740 return Detail::complete_invoke(CATCH_FORWARD(fun));
1741 }
1742 } // namespace Benchmark
1743} // namespace Catch
1744
1745#endif // CATCH_COMPLETE_INVOKE_HPP_INCLUDED
1746
1747
1748// Adapted from donated nonius code.
1749
1750#ifndef CATCH_TIMING_HPP_INCLUDED
1751#define CATCH_TIMING_HPP_INCLUDED
1752
1753
1754#include <type_traits>
1755
1756namespace Catch {
1757 namespace Benchmark {
1758 template <typename Result>
1759 struct Timing {
1760 IDuration elapsed;
1761 Result result;
1762 int iterations;
1763 };
1764 template <typename Func, typename... Args>
1765 using TimingOf = Timing<Detail::CompleteType_t<FunctionReturnType<Func, Args...>>>;
1766 } // namespace Benchmark
1767} // namespace Catch
1768
1769#endif // CATCH_TIMING_HPP_INCLUDED
1770
1771namespace Catch {
1772 namespace Benchmark {
1773 namespace Detail {
1774 template <typename Clock, typename Fun, typename... Args>
1775 TimingOf<Fun, Args...> measure(Fun&& fun, Args&&... args) {
1776 auto start = Clock::now();
1777 auto&& r = Detail::complete_invoke(CATCH_FORWARD(fun), CATCH_FORWARD(args)...);
1778 auto end = Clock::now();
1779 auto delta = end - start;
1780 return { delta, CATCH_FORWARD(r), 1 };
1781 }
1782 } // namespace Detail
1783 } // namespace Benchmark
1784} // namespace Catch
1785
1786#endif // CATCH_MEASURE_HPP_INCLUDED
1787
1788#include <type_traits>
1789
1790namespace Catch {
1791 namespace Benchmark {
1792 namespace Detail {
1793 template <typename Clock, typename Fun>
1794 TimingOf<Fun, int> measure_one(Fun&& fun, int iters, std::false_type) {
1795 return Detail::measure<Clock>(fun, iters);
1796 }
1797 template <typename Clock, typename Fun>
1798 TimingOf<Fun, Chronometer> measure_one(Fun&& fun, int iters, std::true_type) {
1799 Detail::ChronometerModel<Clock> meter;
1800 auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters));
1801
1802 return { meter.elapsed(), CATCH_MOVE(result), iters };
1803 }
1804
1805 template <typename Clock, typename Fun>
1806 using run_for_at_least_argument_t = std::conditional_t<is_callable<Fun(Chronometer)>::value, Chronometer, int>;
1807
1808
1809 [[noreturn]]
1810 void throw_optimized_away_error();
1811
1812 template <typename Clock, typename Fun>
1813 TimingOf<Fun, run_for_at_least_argument_t<Clock, Fun>>
1814 run_for_at_least(IDuration how_long,
1815 const int initial_iterations,
1816 Fun&& fun) {
1817 auto iters = initial_iterations;
1818 while (iters < (1 << 30)) {
1819 auto&& Timing = measure_one<Clock>(fun, iters, is_callable<Fun(Chronometer)>());
1820
1821 if (Timing.elapsed >= how_long) {
1822 return { Timing.elapsed, CATCH_MOVE(Timing.result), iters };
1823 }
1824 iters *= 2;
1825 }
1826 throw_optimized_away_error();
1827 }
1828 } // namespace Detail
1829 } // namespace Benchmark
1830} // namespace Catch
1831
1832#endif // CATCH_RUN_FOR_AT_LEAST_HPP_INCLUDED
1833
1834#include <vector>
1835
1836namespace Catch {
1837 namespace Benchmark {
1838 struct ExecutionPlan {
1839 int iterations_per_sample;
1840 FDuration estimated_duration;
1841 Detail::BenchmarkFunction benchmark;
1842 FDuration warmup_time;
1843 int warmup_iterations;
1844
1845 template <typename Clock>
1846 std::vector<FDuration> run(const IConfig &cfg, Environment env) const {
1847 // warmup a bit
1848 Detail::run_for_at_least<Clock>(
1849 std::chrono::duration_cast<IDuration>( warmup_time ),
1850 warmup_iterations,
1851 Detail::repeat( []() { return Clock::now(); } )
1852 );
1853
1854 std::vector<FDuration> times;
1855 const auto num_samples = cfg.benchmarkSamples();
1856 times.reserve( num_samples );
1857 for ( size_t i = 0; i < num_samples; ++i ) {
1858 Detail::ChronometerModel<Clock> model;
1859 this->benchmark( Chronometer( model, iterations_per_sample ) );
1860 auto sample_time = model.elapsed() - env.clock_cost.mean;
1861 if ( sample_time < FDuration::zero() ) {
1862 sample_time = FDuration::zero();
1863 }
1864 times.push_back(sample_time / iterations_per_sample);
1865 }
1866 return times;
1867 }
1868 };
1869 } // namespace Benchmark
1870} // namespace Catch
1871
1872#endif // CATCH_EXECUTION_PLAN_HPP_INCLUDED
1873
1874
1875// Adapted from donated nonius code.
1876
1877#ifndef CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
1878#define CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
1879
1880
1881
1882// Adapted from donated nonius code.
1883
1884#ifndef CATCH_STATS_HPP_INCLUDED
1885#define CATCH_STATS_HPP_INCLUDED
1886
1887
1888#include <vector>
1889
1890namespace Catch {
1891 namespace Benchmark {
1892 namespace Detail {
1893 using sample = std::vector<double>;
1894
1895 double weighted_average_quantile( int k,
1896 int q,
1897 double* first,
1898 double* last );
1899
1900 OutlierClassification
1901 classify_outliers( double const* first, double const* last );
1902
1903 double mean( double const* first, double const* last );
1904
1905 double normal_cdf( double x );
1906
1907 double erfc_inv(double x);
1908
1909 double normal_quantile(double p);
1910
1911 Estimate<double>
1912 bootstrap( double confidence_level,
1913 double* first,
1914 double* last,
1915 sample const& resample,
1916 double ( *estimator )( double const*, double const* ) );
1917
1918 struct bootstrap_analysis {
1919 Estimate<double> mean;
1920 Estimate<double> standard_deviation;
1921 double outlier_variance;
1922 };
1923
1924 bootstrap_analysis analyse_samples(double confidence_level,
1925 unsigned int n_resamples,
1926 double* first,
1927 double* last);
1928 } // namespace Detail
1929 } // namespace Benchmark
1930} // namespace Catch
1931
1932#endif // CATCH_STATS_HPP_INCLUDED
1933
1934#include <algorithm>
1935#include <vector>
1936#include <cmath>
1937
1938namespace Catch {
1939 namespace Benchmark {
1940 namespace Detail {
1941 template <typename Clock>
1942 std::vector<double> resolution(int k) {
1943 const size_t points = static_cast<size_t>( k + 1 );
1944 // To avoid overhead from the branch inside vector::push_back,
1945 // we allocate them all and then overwrite.
1946 std::vector<TimePoint<Clock>> times(points);
1947 for ( auto& time : times ) {
1948 time = Clock::now();
1949 }
1950
1951 std::vector<double> deltas;
1952 deltas.reserve(static_cast<size_t>(k));
1953 for ( size_t idx = 1; idx < points; ++idx ) {
1954 deltas.push_back( static_cast<double>(
1955 ( times[idx] - times[idx - 1] ).count() ) );
1956 }
1957
1958 return deltas;
1959 }
1960
1961 constexpr auto warmup_iterations = 10000;
1962 constexpr auto warmup_time = std::chrono::milliseconds(100);
1963 constexpr auto minimum_ticks = 1000;
1964 constexpr auto warmup_seed = 10000;
1965 constexpr auto clock_resolution_estimation_time = std::chrono::milliseconds(500);
1966 constexpr auto clock_cost_estimation_time_limit = std::chrono::seconds(1);
1967 constexpr auto clock_cost_estimation_tick_limit = 100000;
1968 constexpr auto clock_cost_estimation_time = std::chrono::milliseconds(10);
1969 constexpr auto clock_cost_estimation_iterations = 10000;
1970
1971 template <typename Clock>
1972 int warmup() {
1973 return run_for_at_least<Clock>(warmup_time, warmup_seed, &resolution<Clock>)
1974 .iterations;
1975 }
1976 template <typename Clock>
1977 EnvironmentEstimate estimate_clock_resolution(int iterations) {
1978 auto r = run_for_at_least<Clock>(clock_resolution_estimation_time, iterations, &resolution<Clock>)
1979 .result;
1980 return {
1981 FDuration(mean(r.data(), r.data() + r.size())),
1982 classify_outliers(r.data(), r.data() + r.size()),
1983 };
1984 }
1985 template <typename Clock>
1986 EnvironmentEstimate estimate_clock_cost(FDuration resolution) {
1987 auto time_limit = (std::min)(
1988 resolution * clock_cost_estimation_tick_limit,
1989 FDuration(clock_cost_estimation_time_limit));
1990 auto time_clock = [](int k) {
1991 return Detail::measure<Clock>([k] {
1992 for (int i = 0; i < k; ++i) {
1993 volatile auto ignored = Clock::now();
1994 (void)ignored;
1995 }
1996 }).elapsed;
1997 };
1998 time_clock(1);
1999 int iters = clock_cost_estimation_iterations;
2000 auto&& r = run_for_at_least<Clock>(clock_cost_estimation_time, iters, time_clock);
2001 std::vector<double> times;
2002 int nsamples = static_cast<int>(std::ceil(time_limit / r.elapsed));
2003 times.reserve(static_cast<size_t>(nsamples));
2004 for ( int s = 0; s < nsamples; ++s ) {
2005 times.push_back( static_cast<double>(
2006 ( time_clock( r.iterations ) / r.iterations )
2007 .count() ) );
2008 }
2009 return {
2010 FDuration(mean(times.data(), times.data() + times.size())),
2011 classify_outliers(times.data(), times.data() + times.size()),
2012 };
2013 }
2014
2015 template <typename Clock>
2016 Environment measure_environment() {
2017#if defined(__clang__)
2018# pragma clang diagnostic push
2019# pragma clang diagnostic ignored "-Wexit-time-destructors"
2020#endif
2021 static Catch::Detail::unique_ptr<Environment> env;
2022#if defined(__clang__)
2023# pragma clang diagnostic pop
2024#endif
2025 if (env) {
2026 return *env;
2027 }
2028
2029 auto iters = Detail::warmup<Clock>();
2030 auto resolution = Detail::estimate_clock_resolution<Clock>(iters);
2031 auto cost = Detail::estimate_clock_cost<Clock>(resolution.mean);
2032
2033 env = Catch::Detail::make_unique<Environment>( Environment{resolution, cost} );
2034 return *env;
2035 }
2036 } // namespace Detail
2037 } // namespace Benchmark
2038} // namespace Catch
2039
2040#endif // CATCH_ESTIMATE_CLOCK_HPP_INCLUDED
2041
2042
2043// Adapted from donated nonius code.
2044
2045#ifndef CATCH_ANALYSE_HPP_INCLUDED
2046#define CATCH_ANALYSE_HPP_INCLUDED
2047
2048
2049
2050// Adapted from donated nonius code.
2051
2052#ifndef CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
2053#define CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
2054
2055
2056#include <vector>
2057
2058namespace Catch {
2059 namespace Benchmark {
2060 struct SampleAnalysis {
2061 std::vector<FDuration> samples;
2062 Estimate<FDuration> mean;
2063 Estimate<FDuration> standard_deviation;
2064 OutlierClassification outliers;
2065 double outlier_variance;
2066 };
2067 } // namespace Benchmark
2068} // namespace Catch
2069
2070#endif // CATCH_SAMPLE_ANALYSIS_HPP_INCLUDED
2071
2072
2073namespace Catch {
2074 class IConfig;
2075
2076 namespace Benchmark {
2077 namespace Detail {
2078 SampleAnalysis analyse(const IConfig &cfg, FDuration* first, FDuration* last);
2079 } // namespace Detail
2080 } // namespace Benchmark
2081} // namespace Catch
2082
2083#endif // CATCH_ANALYSE_HPP_INCLUDED
2084
2085#include <algorithm>
2086#include <chrono>
2087#include <exception>
2088#include <string>
2089#include <cmath>
2090
2091namespace Catch {
2092 namespace Benchmark {
2093 struct Benchmark {
2094 Benchmark(std::string&& benchmarkName)
2095 : name(CATCH_MOVE(benchmarkName)) {}
2096
2097 template <class FUN>
2098 Benchmark(std::string&& benchmarkName , FUN &&func)
2099 : fun(CATCH_MOVE(func)), name(CATCH_MOVE(benchmarkName)) {}
2100
2101 template <typename Clock>
2102 ExecutionPlan prepare(const IConfig &cfg, Environment env) {
2103 auto min_time = env.clock_resolution.mean * Detail::minimum_ticks;
2104 auto run_time = std::max(min_time, std::chrono::duration_cast<decltype(min_time)>(cfg.benchmarkWarmupTime()));
2105 auto&& test = Detail::run_for_at_least<Clock>(std::chrono::duration_cast<IDuration>(run_time), 1, fun);
2106 int new_iters = static_cast<int>(std::ceil(min_time * test.iterations / test.elapsed));
2107 return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), CATCH_MOVE(fun), std::chrono::duration_cast<FDuration>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations };
2108 }
2109
2110 template <typename Clock = default_clock>
2111 void run() {
2112 static_assert( Clock::is_steady,
2113 "Benchmarking clock should be steady" );
2114 auto const* cfg = getCurrentContext().getConfig();
2115
2116 auto env = Detail::measure_environment<Clock>();
2117
2118 getResultCapture().benchmarkPreparing(name);
2119 CATCH_TRY{
2120 auto plan = user_code([&] {
2121 return prepare<Clock>(*cfg, env);
2122 });
2123
2124 BenchmarkInfo info {
2125 CATCH_MOVE(name),
2126 plan.estimated_duration.count(),
2127 plan.iterations_per_sample,
2128 cfg->benchmarkSamples(),
2129 cfg->benchmarkResamples(),
2130 env.clock_resolution.mean.count(),
2131 env.clock_cost.mean.count()
2132 };
2133
2134 getResultCapture().benchmarkStarting(info);
2135
2136 auto samples = user_code([&] {
2137 return plan.template run<Clock>(*cfg, env);
2138 });
2139
2140 auto analysis = Detail::analyse(*cfg, samples.data(), samples.data() + samples.size());
2141 BenchmarkStats<> stats{ CATCH_MOVE(info), CATCH_MOVE(analysis.samples), analysis.mean, analysis.standard_deviation, analysis.outliers, analysis.outlier_variance };
2142 getResultCapture().benchmarkEnded(stats);
2143 } CATCH_CATCH_ANON (TestFailureException const&) {
2144 getResultCapture().benchmarkFailed("Benchmark failed due to failed assertion"_sr);
2145 } CATCH_CATCH_ALL{
2146 getResultCapture().benchmarkFailed(translateActiveException());
2147 // We let the exception go further up so that the
2148 // test case is marked as failed.
2149 std::rethrow_exception(std::current_exception());
2150 }
2151 }
2152
2153 // sets lambda to be used in fun *and* executes benchmark!
2154 template <typename Fun, std::enable_if_t<!Detail::is_related<Fun, Benchmark>::value, int> = 0>
2155 Benchmark & operator=(Fun func) {
2156 auto const* cfg = getCurrentContext().getConfig();
2157 if (!cfg->skipBenchmarks()) {
2158 fun = Detail::BenchmarkFunction(func);
2159 run();
2160 }
2161 return *this;
2162 }
2163
2164 explicit operator bool() {
2165 return true;
2166 }
2167
2168 private:
2169 Detail::BenchmarkFunction fun;
2170 std::string name;
2171 };
2172 }
2173} // namespace Catch
2174
2175#define INTERNAL_CATCH_GET_1_ARG(arg1, arg2, ...) arg1
2176#define INTERNAL_CATCH_GET_2_ARG(arg1, arg2, ...) arg2
2177
2178#define INTERNAL_CATCH_BENCHMARK(BenchmarkName, name, benchmarkIndex)\
2179 if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
2180 BenchmarkName = [&](int benchmarkIndex)
2181
2182#define INTERNAL_CATCH_BENCHMARK_ADVANCED(BenchmarkName, name)\
2183 if( Catch::Benchmark::Benchmark BenchmarkName{name} ) \
2184 BenchmarkName = [&]
2185
2186#if defined(CATCH_CONFIG_PREFIX_ALL)
2187
2188#define CATCH_BENCHMARK(...) \
2189 INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
2190#define CATCH_BENCHMARK_ADVANCED(name) \
2191 INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
2192
2193#else
2194
2195#define BENCHMARK(...) \
2196 INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,))
2197#define BENCHMARK_ADVANCED(name) \
2198 INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(CATCH2_INTERNAL_BENCHMARK_), name)
2199
2200#endif
2201
2202#endif // CATCH_BENCHMARK_HPP_INCLUDED
2203
2204
2205// Adapted from donated nonius code.
2206
2207#ifndef CATCH_CONSTRUCTOR_HPP_INCLUDED
2208#define CATCH_CONSTRUCTOR_HPP_INCLUDED
2209
2210
2211#include <type_traits>
2212
2213namespace Catch {
2214 namespace Benchmark {
2215 namespace Detail {
2216 template <typename T, bool Destruct>
2217 struct ObjectStorage
2218 {
2219 ObjectStorage() = default;
2220
2221 ObjectStorage(const ObjectStorage& other)
2222 {
2223 new(&data) T(other.stored_object());
2224 }
2225
2226 ObjectStorage(ObjectStorage&& other)
2227 {
2228 new(data) T(CATCH_MOVE(other.stored_object()));
2229 }
2230
2231 ~ObjectStorage() { destruct_on_exit<T>(); }
2232
2233 template <typename... Args>
2234 void construct(Args&&... args)
2235 {
2236 new (data) T(CATCH_FORWARD(args)...);
2237 }
2238
2239 template <bool AllowManualDestruction = !Destruct>
2240 std::enable_if_t<AllowManualDestruction> destruct()
2241 {
2242 stored_object().~T();
2243 }
2244
2245 private:
2246 // If this is a constructor benchmark, destruct the underlying object
2247 template <typename U>
2248 void destruct_on_exit(std::enable_if_t<Destruct, U>* = nullptr) { destruct<true>(); }
2249 // Otherwise, don't
2250 template <typename U>
2251 void destruct_on_exit(std::enable_if_t<!Destruct, U>* = nullptr) { }
2252
2253#if defined( __GNUC__ ) && __GNUC__ <= 6
2254# pragma GCC diagnostic push
2255# pragma GCC diagnostic ignored "-Wstrict-aliasing"
2256#endif
2257 T& stored_object() { return *reinterpret_cast<T*>( data ); }
2258
2259 T const& stored_object() const {
2260 return *reinterpret_cast<T const*>( data );
2261 }
2262#if defined( __GNUC__ ) && __GNUC__ <= 6
2263# pragma GCC diagnostic pop
2264#endif
2265
2266 alignas( T ) unsigned char data[sizeof( T )]{};
2267 };
2268 } // namespace Detail
2269
2270 template <typename T>
2271 using storage_for = Detail::ObjectStorage<T, true>;
2272
2273 template <typename T>
2274 using destructable_object = Detail::ObjectStorage<T, false>;
2275 } // namespace Benchmark
2276} // namespace Catch
2277
2278#endif // CATCH_CONSTRUCTOR_HPP_INCLUDED
2279
2280#endif // CATCH_BENCHMARK_ALL_HPP_INCLUDED
2281
2282
2283#ifndef CATCH_APPROX_HPP_INCLUDED
2284#define CATCH_APPROX_HPP_INCLUDED
2285
2286
2287
2288#ifndef CATCH_TOSTRING_HPP_INCLUDED
2289#define CATCH_TOSTRING_HPP_INCLUDED
2290
2291
2292#include <vector>
2293#include <cstddef>
2294#include <type_traits>
2295#include <string>
2296
2297
2298
2299
2300/** \file
2301 * Wrapper for the WCHAR configuration option
2302 *
2303 * We want to support platforms that do not provide `wchar_t`, so we
2304 * sometimes have to disable providing wchar_t overloads through Catch2,
2305 * e.g. the StringMaker specialization for `std::wstring`.
2306 */
2307
2308#ifndef CATCH_CONFIG_WCHAR_HPP_INCLUDED
2309#define CATCH_CONFIG_WCHAR_HPP_INCLUDED
2310
2311
2312// We assume that WCHAR should be enabled by default, and only disabled
2313// for a shortlist (so far only DJGPP) of compilers.
2314
2315#if defined(__DJGPP__)
2316# define CATCH_INTERNAL_CONFIG_NO_WCHAR
2317#endif // __DJGPP__
2318
2319#if !defined( CATCH_INTERNAL_CONFIG_NO_WCHAR ) && \
2320 !defined( CATCH_CONFIG_NO_WCHAR ) && \
2321 !defined( CATCH_CONFIG_WCHAR )
2322# define CATCH_CONFIG_WCHAR
2323#endif
2324
2325#endif // CATCH_CONFIG_WCHAR_HPP_INCLUDED
2326
2327
2328#ifndef CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
2329#define CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
2330
2331
2332#include <iosfwd>
2333#include <cstddef>
2334#include <ostream>
2335#include <string>
2336
2337namespace Catch {
2338
2339 class ReusableStringStream : Detail::NonCopyable {
2340 std::size_t m_index;
2341 std::ostream* m_oss;
2342 public:
2343 ReusableStringStream();
2344 ~ReusableStringStream();
2345
2346 //! Returns the serialized state
2347 std::string str() const;
2348 //! Sets internal state to `str`
2349 void str(std::string const& str);
2350
2351#if defined(__GNUC__) && !defined(__clang__)
2352#pragma GCC diagnostic push
2353// Old versions of GCC do not understand -Wnonnull-compare
2354#pragma GCC diagnostic ignored "-Wpragmas"
2355// Streaming a function pointer triggers Waddress and Wnonnull-compare
2356// on GCC, because it implicitly converts it to bool and then decides
2357// that the check it uses (a? true : false) is tautological and cannot
2358// be null...
2359#pragma GCC diagnostic ignored "-Waddress"
2360#pragma GCC diagnostic ignored "-Wnonnull-compare"
2361#endif
2362
2363 template<typename T>
2364 auto operator << ( T const& value ) -> ReusableStringStream& {
2365 *m_oss << value;
2366 return *this;
2367 }
2368
2369#if defined(__GNUC__) && !defined(__clang__)
2370#pragma GCC diagnostic pop
2371#endif
2372 auto get() -> std::ostream& { return *m_oss; }
2373 };
2374}
2375
2376#endif // CATCH_REUSABLE_STRING_STREAM_HPP_INCLUDED
2377
2378
2379#ifndef CATCH_VOID_TYPE_HPP_INCLUDED
2380#define CATCH_VOID_TYPE_HPP_INCLUDED
2381
2382
2383namespace Catch {
2384 namespace Detail {
2385
2386 template <typename...>
2387 struct make_void { using type = void; };
2388
2389 template <typename... Ts>
2390 using void_t = typename make_void<Ts...>::type;
2391
2392 } // namespace Detail
2393} // namespace Catch
2394
2395
2396#endif // CATCH_VOID_TYPE_HPP_INCLUDED
2397
2398
2399#ifndef CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
2400#define CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
2401
2402
2403#include <vector>
2404
2405namespace Catch {
2406
2407 namespace Detail {
2408 struct EnumInfo {
2409 StringRef m_name;
2410 std::vector<std::pair<int, StringRef>> m_values;
2411
2412 ~EnumInfo();
2413
2414 StringRef lookup( int value ) const;
2415 };
2416 } // namespace Detail
2417
2418 class IMutableEnumValuesRegistry {
2419 public:
2420 virtual ~IMutableEnumValuesRegistry(); // = default;
2421
2422 virtual Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::vector<int> const& values ) = 0;
2423
2424 template<typename E>
2425 Detail::EnumInfo const& registerEnum( StringRef enumName, StringRef allEnums, std::initializer_list<E> values ) {
2426 static_assert(sizeof(int) >= sizeof(E), "Cannot serialize enum to int");
2427 std::vector<int> intValues;
2428 intValues.reserve( values.size() );
2429 for( auto enumValue : values )
2430 intValues.push_back( static_cast<int>( enumValue ) );
2431 return registerEnum( enumName, allEnums, intValues );
2432 }
2433 };
2434
2435} // Catch
2436
2437#endif // CATCH_INTERFACES_ENUM_VALUES_REGISTRY_HPP_INCLUDED
2438
2439#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2440#include <string_view>
2441#endif
2442
2443#ifdef _MSC_VER
2444#pragma warning(push)
2445#pragma warning(disable:4180) // We attempt to stream a function (address) by const&, which MSVC complains about but is harmless
2446#endif
2447
2448// We need a dummy global operator<< so we can bring it into Catch namespace later
2449struct Catch_global_namespace_dummy{};
2450std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy);
2451
2452namespace Catch {
2453 // Bring in global namespace operator<< for ADL lookup in
2454 // `IsStreamInsertable` below.
2455 using ::operator<<;
2456
2457 namespace Detail {
2458
2459 inline std::size_t catch_strnlen(const char *str, std::size_t n) {
2460 auto ret = std::char_traits<char>::find(str, n, '\0');
2461 if (ret != nullptr) {
2462 return static_cast<std::size_t>(ret - str);
2463 }
2464 return n;
2465 }
2466
2467 constexpr StringRef unprintableString = "{?}"_sr;
2468
2469 //! Encases `string in quotes, and optionally escapes invisibles
2470 std::string convertIntoString( StringRef string, bool escapeInvisibles );
2471
2472 //! Encases `string` in quotes, and escapes invisibles if user requested
2473 //! it via CLI
2474 std::string convertIntoString( StringRef string );
2475
2476 std::string rawMemoryToString( const void *object, std::size_t size );
2477
2478 template<typename T>
2479 std::string rawMemoryToString( const T& object ) {
2480 return rawMemoryToString( &object, sizeof(object) );
2481 }
2482
2483 template<typename T>
2484 class IsStreamInsertable {
2485 template<typename Stream, typename U>
2486 static auto test(int)
2487 -> decltype(std::declval<Stream&>() << std::declval<U>(), std::true_type());
2488
2489 template<typename, typename>
2490 static auto test(...)->std::false_type;
2491
2492 public:
2493 static const bool value = decltype(test<std::ostream, const T&>(0))::value;
2494 };
2495
2496 template<typename E>
2497 std::string convertUnknownEnumToString( E e );
2498
2499 template<typename T>
2500 std::enable_if_t<
2501 !std::is_enum<T>::value && !std::is_base_of<std::exception, T>::value,
2502 std::string> convertUnstreamable( T const& ) {
2503 return std::string(Detail::unprintableString);
2504 }
2505 template<typename T>
2506 std::enable_if_t<
2507 !std::is_enum<T>::value && std::is_base_of<std::exception, T>::value,
2508 std::string> convertUnstreamable(T const& ex) {
2509 return ex.what();
2510 }
2511
2512
2513 template<typename T>
2514 std::enable_if_t<
2515 std::is_enum<T>::value,
2516 std::string> convertUnstreamable( T const& value ) {
2517 return convertUnknownEnumToString( value );
2518 }
2519
2520#if defined(_MANAGED)
2521 //! Convert a CLR string to a utf8 std::string
2522 template<typename T>
2523 std::string clrReferenceToString( T^ ref ) {
2524 if (ref == nullptr)
2525 return std::string("null");
2526 auto bytes = System::Text::Encoding::UTF8->GetBytes(ref->ToString());
2527 cli::pin_ptr<System::Byte> p = &bytes[0];
2528 return std::string(reinterpret_cast<char const *>(p), bytes->Length);
2529 }
2530#endif
2531
2532 } // namespace Detail
2533
2534
2535 template <typename T, typename = void>
2536 struct StringMaker {
2537 template <typename Fake = T>
2538 static
2539 std::enable_if_t<::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
2540 convert(const Fake& value) {
2541 ReusableStringStream rss;
2542 // NB: call using the function-like syntax to avoid ambiguity with
2543 // user-defined templated operator<< under clang.
2544 rss.operator<<(value);
2545 return rss.str();
2546 }
2547
2548 template <typename Fake = T>
2549 static
2550 std::enable_if_t<!::Catch::Detail::IsStreamInsertable<Fake>::value, std::string>
2551 convert( const Fake& value ) {
2552#if !defined(CATCH_CONFIG_FALLBACK_STRINGIFIER)
2553 return Detail::convertUnstreamable(value);
2554#else
2555 return CATCH_CONFIG_FALLBACK_STRINGIFIER(value);
2556#endif
2557 }
2558 };
2559
2560 namespace Detail {
2561
2562 // This function dispatches all stringification requests inside of Catch.
2563 // Should be preferably called fully qualified, like ::Catch::Detail::stringify
2564 template <typename T>
2565 std::string stringify(const T& e) {
2566 return ::Catch::StringMaker<std::remove_cv_t<std::remove_reference_t<T>>>::convert(e);
2567 }
2568
2569 template<typename E>
2570 std::string convertUnknownEnumToString( E e ) {
2571 return ::Catch::Detail::stringify(static_cast<std::underlying_type_t<E>>(e));
2572 }
2573
2574#if defined(_MANAGED)
2575 template <typename T>
2576 std::string stringify( T^ e ) {
2577 return ::Catch::StringMaker<T^>::convert(e);
2578 }
2579#endif
2580
2581 } // namespace Detail
2582
2583 // Some predefined specializations
2584
2585 template<>
2586 struct StringMaker<std::string> {
2587 static std::string convert(const std::string& str);
2588 };
2589
2590#ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2591 template<>
2592 struct StringMaker<std::string_view> {
2593 static std::string convert(std::string_view str);
2594 };
2595#endif
2596
2597 template<>
2598 struct StringMaker<char const *> {
2599 static std::string convert(char const * str);
2600 };
2601 template<>
2602 struct StringMaker<char *> {
2603 static std::string convert(char * str);
2604 };
2605
2606#if defined(CATCH_CONFIG_WCHAR)
2607 template<>
2608 struct StringMaker<std::wstring> {
2609 static std::string convert(const std::wstring& wstr);
2610 };
2611
2612# ifdef CATCH_CONFIG_CPP17_STRING_VIEW
2613 template<>
2614 struct StringMaker<std::wstring_view> {
2615 static std::string convert(std::wstring_view str);
2616 };
2617# endif
2618
2619 template<>
2620 struct StringMaker<wchar_t const *> {
2621 static std::string convert(wchar_t const * str);
2622 };
2623 template<>
2624 struct StringMaker<wchar_t *> {
2625 static std::string convert(wchar_t * str);
2626 };
2627#endif // CATCH_CONFIG_WCHAR
2628
2629 template<size_t SZ>
2630 struct StringMaker<char[SZ]> {
2631 static std::string convert(char const* str) {
2632 return Detail::convertIntoString(
2633 StringRef( str, Detail::catch_strnlen( str, SZ ) ) );
2634 }
2635 };
2636 template<size_t SZ>
2637 struct StringMaker<signed char[SZ]> {
2638 static std::string convert(signed char const* str) {
2639 auto reinterpreted = reinterpret_cast<char const*>(str);
2640 return Detail::convertIntoString(
2641 StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
2642 }
2643 };
2644 template<size_t SZ>
2645 struct StringMaker<unsigned char[SZ]> {
2646 static std::string convert(unsigned char const* str) {
2647 auto reinterpreted = reinterpret_cast<char const*>(str);
2648 return Detail::convertIntoString(
2649 StringRef(reinterpreted, Detail::catch_strnlen(reinterpreted, SZ)));
2650 }
2651 };
2652
2653#if defined(CATCH_CONFIG_CPP17_BYTE)
2654 template<>
2655 struct StringMaker<std::byte> {
2656 static std::string convert(std::byte value);
2657 };
2658#endif // defined(CATCH_CONFIG_CPP17_BYTE)
2659 template<>
2660 struct StringMaker<int> {
2661 static std::string convert(int value);
2662 };
2663 template<>
2664 struct StringMaker<long> {
2665 static std::string convert(long value);
2666 };
2667 template<>
2668 struct StringMaker<long long> {
2669 static std::string convert(long long value);
2670 };
2671 template<>
2672 struct StringMaker<unsigned int> {
2673 static std::string convert(unsigned int value);
2674 };
2675 template<>
2676 struct StringMaker<unsigned long> {
2677 static std::string convert(unsigned long value);
2678 };
2679 template<>
2680 struct StringMaker<unsigned long long> {
2681 static std::string convert(unsigned long long value);
2682 };
2683
2684 template<>
2685 struct StringMaker<bool> {
2686 static std::string convert(bool b) {
2687 using namespace std::string_literals;
2688 return b ? "true"s : "false"s;
2689 }
2690 };
2691
2692 template<>
2693 struct StringMaker<char> {
2694 static std::string convert(char c);
2695 };
2696 template<>
2697 struct StringMaker<signed char> {
2698 static std::string convert(signed char value);
2699 };
2700 template<>
2701 struct StringMaker<unsigned char> {
2702 static std::string convert(unsigned char value);
2703 };
2704
2705 template<>
2706 struct StringMaker<std::nullptr_t> {
2707 static std::string convert(std::nullptr_t) {
2708 using namespace std::string_literals;
2709 return "nullptr"s;
2710 }
2711 };
2712
2713 template<>
2714 struct StringMaker<float> {
2715 static std::string convert(float value);
2716 CATCH_EXPORT static int precision;
2717 };
2718
2719 template<>
2720 struct StringMaker<double> {
2721 static std::string convert(double value);
2722 CATCH_EXPORT static int precision;
2723 };
2724
2725 template <typename T>
2726 struct StringMaker<T*> {
2727 template <typename U>
2728 static std::string convert(U* p) {
2729 if (p) {
2730 return ::Catch::Detail::rawMemoryToString(p);
2731 } else {
2732 return "nullptr";
2733 }
2734 }
2735 };
2736
2737 template <typename R, typename C>
2738 struct StringMaker<R C::*> {
2739 static std::string convert(R C::* p) {
2740 if (p) {
2741 return ::Catch::Detail::rawMemoryToString(p);
2742 } else {
2743 return "nullptr";
2744 }
2745 }
2746 };
2747
2748#if defined(_MANAGED)
2749 template <typename T>
2750 struct StringMaker<T^> {
2751 static std::string convert( T^ ref ) {
2752 return ::Catch::Detail::clrReferenceToString(ref);
2753 }
2754 };
2755#endif
2756
2757 namespace Detail {
2758 template<typename InputIterator, typename Sentinel = InputIterator>
2759 std::string rangeToString(InputIterator first, Sentinel last) {
2760 ReusableStringStream rss;
2761 rss << "{ ";
2762 if (first != last) {
2763 rss << ::Catch::Detail::stringify(*first);
2764 for (++first; first != last; ++first)
2765 rss << ", " << ::Catch::Detail::stringify(*first);
2766 }
2767 rss << " }";
2768 return rss.str();
2769 }
2770 }
2771
2772} // namespace Catch
2773
2774//////////////////////////////////////////////////////
2775// Separate std-lib types stringification, so it can be selectively enabled
2776// This means that we do not bring in their headers
2777
2778#if defined(CATCH_CONFIG_ENABLE_ALL_STRINGMAKERS)
2779# define CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
2780# define CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
2781# define CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
2782# define CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
2783#endif
2784
2785// Separate std::pair specialization
2786#if defined(CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER)
2787#include <utility>
2788namespace Catch {
2789 template<typename T1, typename T2>
2790 struct StringMaker<std::pair<T1, T2> > {
2791 static std::string convert(const std::pair<T1, T2>& pair) {
2792 ReusableStringStream rss;
2793 rss << "{ "
2794 << ::Catch::Detail::stringify(pair.first)
2795 << ", "
2796 << ::Catch::Detail::stringify(pair.second)
2797 << " }";
2798 return rss.str();
2799 }
2800 };
2801}
2802#endif // CATCH_CONFIG_ENABLE_PAIR_STRINGMAKER
2803
2804#if defined(CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_OPTIONAL)
2805#include <optional>
2806namespace Catch {
2807 template<typename T>
2808 struct StringMaker<std::optional<T> > {
2809 static std::string convert(const std::optional<T>& optional) {
2810 if (optional.has_value()) {
2811 return ::Catch::Detail::stringify(*optional);
2812 } else {
2813 return "{ }";
2814 }
2815 }
2816 };
2817 template <>
2818 struct StringMaker<std::nullopt_t> {
2819 static std::string convert(const std::nullopt_t&) {
2820 return "{ }";
2821 }
2822 };
2823}
2824#endif // CATCH_CONFIG_ENABLE_OPTIONAL_STRINGMAKER
2825
2826// Separate std::tuple specialization
2827#if defined(CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER)
2828#include <tuple>
2829namespace Catch {
2830 namespace Detail {
2831 template<
2832 typename Tuple,
2833 std::size_t N = 0,
2834 bool = (N < std::tuple_size<Tuple>::value)
2835 >
2836 struct TupleElementPrinter {
2837 static void print(const Tuple& tuple, std::ostream& os) {
2838 os << (N ? ", " : " ")
2839 << ::Catch::Detail::stringify(std::get<N>(tuple));
2840 TupleElementPrinter<Tuple, N + 1>::print(tuple, os);
2841 }
2842 };
2843
2844 template<
2845 typename Tuple,
2846 std::size_t N
2847 >
2848 struct TupleElementPrinter<Tuple, N, false> {
2849 static void print(const Tuple&, std::ostream&) {}
2850 };
2851
2852 }
2853
2854
2855 template<typename ...Types>
2856 struct StringMaker<std::tuple<Types...>> {
2857 static std::string convert(const std::tuple<Types...>& tuple) {
2858 ReusableStringStream rss;
2859 rss << '{';
2860 Detail::TupleElementPrinter<std::tuple<Types...>>::print(tuple, rss.get());
2861 rss << " }";
2862 return rss.str();
2863 }
2864 };
2865}
2866#endif // CATCH_CONFIG_ENABLE_TUPLE_STRINGMAKER
2867
2868#if defined(CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER) && defined(CATCH_CONFIG_CPP17_VARIANT)
2869#include <variant>
2870namespace Catch {
2871 template<>
2872 struct StringMaker<std::monostate> {
2873 static std::string convert(const std::monostate&) {
2874 return "{ }";
2875 }
2876 };
2877
2878 template<typename... Elements>
2879 struct StringMaker<std::variant<Elements...>> {
2880 static std::string convert(const std::variant<Elements...>& variant) {
2881 if (variant.valueless_by_exception()) {
2882 return "{valueless variant}";
2883 } else {
2884 return std::visit(
2885 [](const auto& value) {
2886 return ::Catch::Detail::stringify(value);
2887 },
2888 variant
2889 );
2890 }
2891 }
2892 };
2893}
2894#endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER
2895
2896namespace Catch {
2897 // Import begin/ end from std here
2898 using std::begin;
2899 using std::end;
2900
2901 namespace Detail {
2902 template <typename T, typename = void>
2903 struct is_range_impl : std::false_type {};
2904
2905 template <typename T>
2906 struct is_range_impl<T, void_t<decltype(begin(std::declval<T>()))>> : std::true_type {};
2907 } // namespace Detail
2908
2909 template <typename T>
2910 struct is_range : Detail::is_range_impl<T> {};
2911
2912#if defined(_MANAGED) // Managed types are never ranges
2913 template <typename T>
2914 struct is_range<T^> {
2915 static const bool value = false;
2916 };
2917#endif
2918
2919 template<typename Range>
2920 std::string rangeToString( Range const& range ) {
2921 return ::Catch::Detail::rangeToString( begin( range ), end( range ) );
2922 }
2923
2924 // Handle vector<bool> specially
2925 template<typename Allocator>
2926 std::string rangeToString( std::vector<bool, Allocator> const& v ) {
2927 ReusableStringStream rss;
2928 rss << "{ ";
2929 bool first = true;
2930 for( bool b : v ) {
2931 if( first )
2932 first = false;
2933 else
2934 rss << ", ";
2935 rss << ::Catch::Detail::stringify( b );
2936 }
2937 rss << " }";
2938 return rss.str();
2939 }
2940
2941 template<typename R>
2942 struct StringMaker<R, std::enable_if_t<is_range<R>::value && !::Catch::Detail::IsStreamInsertable<R>::value>> {
2943 static std::string convert( R const& range ) {
2944 return rangeToString( range );
2945 }
2946 };
2947
2948 template <typename T, size_t SZ>
2949 struct StringMaker<T[SZ]> {
2950 static std::string convert(T const(&arr)[SZ]) {
2951 return rangeToString(arr);
2952 }
2953 };
2954
2955
2956} // namespace Catch
2957
2958// Separate std::chrono::duration specialization
2959#include <ctime>
2960#include <ratio>
2961#include <chrono>
2962
2963
2964namespace Catch {
2965
2966template <class Ratio>
2967struct ratio_string {
2968 static std::string symbol() {
2969 Catch::ReusableStringStream rss;
2970 rss << '[' << Ratio::num << '/'
2971 << Ratio::den << ']';
2972 return rss.str();
2973 }
2974};
2975
2976template <>
2977struct ratio_string<std::atto> {
2978 static char symbol() { return 'a'; }
2979};
2980template <>
2981struct ratio_string<std::femto> {
2982 static char symbol() { return 'f'; }
2983};
2984template <>
2985struct ratio_string<std::pico> {
2986 static char symbol() { return 'p'; }
2987};
2988template <>
2989struct ratio_string<std::nano> {
2990 static char symbol() { return 'n'; }
2991};
2992template <>
2993struct ratio_string<std::micro> {
2994 static char symbol() { return 'u'; }
2995};
2996template <>
2997struct ratio_string<std::milli> {
2998 static char symbol() { return 'm'; }
2999};
3000
3001 ////////////
3002 // std::chrono::duration specializations
3003 template<typename Value, typename Ratio>
3004 struct StringMaker<std::chrono::duration<Value, Ratio>> {
3005 static std::string convert(std::chrono::duration<Value, Ratio> const& duration) {
3006 ReusableStringStream rss;
3007 rss << duration.count() << ' ' << ratio_string<Ratio>::symbol() << 's';
3008 return rss.str();
3009 }
3010 };
3011 template<typename Value>
3012 struct StringMaker<std::chrono::duration<Value, std::ratio<1>>> {
3013 static std::string convert(std::chrono::duration<Value, std::ratio<1>> const& duration) {
3014 ReusableStringStream rss;
3015 rss << duration.count() << " s";
3016 return rss.str();
3017 }
3018 };
3019 template<typename Value>
3020 struct StringMaker<std::chrono::duration<Value, std::ratio<60>>> {
3021 static std::string convert(std::chrono::duration<Value, std::ratio<60>> const& duration) {
3022 ReusableStringStream rss;
3023 rss << duration.count() << " m";
3024 return rss.str();
3025 }
3026 };
3027 template<typename Value>
3028 struct StringMaker<std::chrono::duration<Value, std::ratio<3600>>> {
3029 static std::string convert(std::chrono::duration<Value, std::ratio<3600>> const& duration) {
3030 ReusableStringStream rss;
3031 rss << duration.count() << " h";
3032 return rss.str();
3033 }
3034 };
3035
3036 ////////////
3037 // std::chrono::time_point specialization
3038 // Generic time_point cannot be specialized, only std::chrono::time_point<system_clock>
3039 template<typename Clock, typename Duration>
3040 struct StringMaker<std::chrono::time_point<Clock, Duration>> {
3041 static std::string convert(std::chrono::time_point<Clock, Duration> const& time_point) {
3042 return ::Catch::Detail::stringify(time_point.time_since_epoch()) + " since epoch";
3043 }
3044 };
3045 // std::chrono::time_point<system_clock> specialization
3046 template<typename Duration>
3047 struct StringMaker<std::chrono::time_point<std::chrono::system_clock, Duration>> {
3048 static std::string convert(std::chrono::time_point<std::chrono::system_clock, Duration> const& time_point) {
3049 auto converted = std::chrono::system_clock::to_time_t(time_point);
3050
3051#ifdef _MSC_VER
3052 std::tm timeInfo = {};
3053 gmtime_s(&timeInfo, &converted);
3054#else
3055 std::tm* timeInfo = std::gmtime(&converted);
3056#endif
3057
3058 auto const timeStampSize = sizeof("2017-01-16T17:06:45Z");
3059 char timeStamp[timeStampSize];
3060 const char * const fmt = "%Y-%m-%dT%H:%M:%SZ";
3061
3062#ifdef _MSC_VER
3063 std::strftime(timeStamp, timeStampSize, fmt, &timeInfo);
3064#else
3065 std::strftime(timeStamp, timeStampSize, fmt, timeInfo);
3066#endif
3067 return std::string(timeStamp, timeStampSize - 1);
3068 }
3069 };
3070}
3071
3072
3073#define INTERNAL_CATCH_REGISTER_ENUM( enumName, ... ) \
3074namespace Catch { \
3075 template<> struct StringMaker<enumName> { \
3076 static std::string convert( enumName value ) { \
3077 static const auto& enumInfo = ::Catch::getMutableRegistryHub().getMutableEnumValuesRegistry().registerEnum( #enumName, #__VA_ARGS__, { __VA_ARGS__ } ); \
3078 return static_cast<std::string>(enumInfo.lookup( static_cast<int>( value ) )); \
3079 } \
3080 }; \
3081}
3082
3083#define CATCH_REGISTER_ENUM( enumName, ... ) INTERNAL_CATCH_REGISTER_ENUM( enumName, __VA_ARGS__ )
3084
3085#ifdef _MSC_VER
3086#pragma warning(pop)
3087#endif
3088
3089#endif // CATCH_TOSTRING_HPP_INCLUDED
3090
3091#include <type_traits>
3092
3093namespace Catch {
3094
3095 class Approx {
3096 private:
3097 bool equalityComparisonImpl(double other) const;
3098 // Sets and validates the new margin (margin >= 0)
3099 void setMargin(double margin);
3100 // Sets and validates the new epsilon (0 < epsilon < 1)
3101 void setEpsilon(double epsilon);
3102
3103 public:
3104 explicit Approx ( double value );
3105
3106 static Approx custom();
3107
3108 Approx operator-() const;
3109
3110 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3111 Approx operator()( T const& value ) const {
3112 Approx approx( static_cast<double>(value) );
3113 approx.m_epsilon = m_epsilon;
3114 approx.m_margin = m_margin;
3115 approx.m_scale = m_scale;
3116 return approx;
3117 }
3118
3119 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3120 explicit Approx( T const& value ): Approx(static_cast<double>(value))
3121 {}
3122
3123
3124 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3125 friend bool operator == ( const T& lhs, Approx const& rhs ) {
3126 auto lhs_v = static_cast<double>(lhs);
3127 return rhs.equalityComparisonImpl(lhs_v);
3128 }
3129
3130 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3131 friend bool operator == ( Approx const& lhs, const T& rhs ) {
3132 return operator==( rhs, lhs );
3133 }
3134
3135 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3136 friend bool operator != ( T const& lhs, Approx const& rhs ) {
3137 return !operator==( lhs, rhs );
3138 }
3139
3140 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3141 friend bool operator != ( Approx const& lhs, T const& rhs ) {
3142 return !operator==( rhs, lhs );
3143 }
3144
3145 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3146 friend bool operator <= ( T const& lhs, Approx const& rhs ) {
3147 return static_cast<double>(lhs) < rhs.m_value || lhs == rhs;
3148 }
3149
3150 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3151 friend bool operator <= ( Approx const& lhs, T const& rhs ) {
3152 return lhs.m_value < static_cast<double>(rhs) || lhs == rhs;
3153 }
3154
3155 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3156 friend bool operator >= ( T const& lhs, Approx const& rhs ) {
3157 return static_cast<double>(lhs) > rhs.m_value || lhs == rhs;
3158 }
3159
3160 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3161 friend bool operator >= ( Approx const& lhs, T const& rhs ) {
3162 return lhs.m_value > static_cast<double>(rhs) || lhs == rhs;
3163 }
3164
3165 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3166 Approx& epsilon( T const& newEpsilon ) {
3167 const auto epsilonAsDouble = static_cast<double>(newEpsilon);
3168 setEpsilon(epsilonAsDouble);
3169 return *this;
3170 }
3171
3172 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3173 Approx& margin( T const& newMargin ) {
3174 const auto marginAsDouble = static_cast<double>(newMargin);
3175 setMargin(marginAsDouble);
3176 return *this;
3177 }
3178
3179 template <typename T, typename = std::enable_if_t<std::is_constructible<double, T>::value>>
3180 Approx& scale( T const& newScale ) {
3181 m_scale = static_cast<double>(newScale);
3182 return *this;
3183 }
3184
3185 std::string toString() const;
3186
3187 private:
3188 double m_epsilon;
3189 double m_margin;
3190 double m_scale;
3191 double m_value;
3192 };
3193
3194namespace literals {
3195 Approx operator ""_a(long double val);
3196 Approx operator ""_a(unsigned long long val);
3197} // end namespace literals
3198
3199template<>
3200struct StringMaker<Catch::Approx> {
3201 static std::string convert(Catch::Approx const& value);
3202};
3203
3204} // end namespace Catch
3205
3206#endif // CATCH_APPROX_HPP_INCLUDED
3207
3208
3209#ifndef CATCH_ASSERTION_INFO_HPP_INCLUDED
3210#define CATCH_ASSERTION_INFO_HPP_INCLUDED
3211
3212
3213
3214#ifndef CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
3215#define CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
3216
3217#include <cstddef>
3218#include <iosfwd>
3219
3220namespace Catch {
3221
3222 struct SourceLineInfo {
3223
3224 SourceLineInfo() = delete;
3225 constexpr SourceLineInfo( char const* _file, std::size_t _line ) noexcept:
3226 file( _file ),
3227 line( _line )
3228 {}
3229
3230 bool operator == ( SourceLineInfo const& other ) const noexcept;
3231 bool operator < ( SourceLineInfo const& other ) const noexcept;
3232
3233 char const* file;
3234 std::size_t line;
3235
3236 friend std::ostream& operator << (std::ostream& os, SourceLineInfo const& info);
3237 };
3238}
3239
3240#define CATCH_INTERNAL_LINEINFO \
3241 ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
3242
3243#endif // CATCH_SOURCE_LINE_INFO_HPP_INCLUDED
3244
3245namespace Catch {
3246
3247 struct AssertionInfo {
3248 // AssertionInfo() = delete;
3249
3250 StringRef macroName;
3251 SourceLineInfo lineInfo;
3252 StringRef capturedExpression;
3253 ResultDisposition::Flags resultDisposition;
3254 };
3255
3256} // end namespace Catch
3257
3258#endif // CATCH_ASSERTION_INFO_HPP_INCLUDED
3259
3260
3261#ifndef CATCH_ASSERTION_RESULT_HPP_INCLUDED
3262#define CATCH_ASSERTION_RESULT_HPP_INCLUDED
3263
3264
3265
3266#ifndef CATCH_LAZY_EXPR_HPP_INCLUDED
3267#define CATCH_LAZY_EXPR_HPP_INCLUDED
3268
3269#include <iosfwd>
3270
3271namespace Catch {
3272
3273 class ITransientExpression;
3274
3275 class LazyExpression {
3276 friend class AssertionHandler;
3277 friend struct AssertionStats;
3278 friend class RunContext;
3279
3280 ITransientExpression const* m_transientExpression = nullptr;
3281 bool m_isNegated;
3282 public:
3283 constexpr LazyExpression( bool isNegated ):
3284 m_isNegated(isNegated)
3285 {}
3286 constexpr LazyExpression(LazyExpression const& other) = default;
3287 LazyExpression& operator = ( LazyExpression const& ) = delete;
3288
3289 constexpr explicit operator bool() const {
3290 return m_transientExpression != nullptr;
3291 }
3292
3293 friend auto operator << ( std::ostream& os, LazyExpression const& lazyExpr ) -> std::ostream&;
3294 };
3295
3296} // namespace Catch
3297
3298#endif // CATCH_LAZY_EXPR_HPP_INCLUDED
3299
3300#include <string>
3301
3302namespace Catch {
3303
3304 struct AssertionResultData
3305 {
3306 AssertionResultData() = delete;
3307
3308 AssertionResultData( ResultWas::OfType _resultType, LazyExpression const& _lazyExpression );
3309
3310 std::string message;
3311 mutable std::string reconstructedExpression;
3312 LazyExpression lazyExpression;
3313 ResultWas::OfType resultType;
3314
3315 std::string reconstructExpression() const;
3316 };
3317
3318 class AssertionResult {
3319 public:
3320 AssertionResult() = delete;
3321 AssertionResult( AssertionInfo const& info, AssertionResultData&& data );
3322
3323 bool isOk() const;
3324 bool succeeded() const;
3325 ResultWas::OfType getResultType() const;
3326 bool hasExpression() const;
3327 bool hasMessage() const;
3328 std::string getExpression() const;
3329 std::string getExpressionInMacro() const;
3330 bool hasExpandedExpression() const;
3331 std::string getExpandedExpression() const;
3332 StringRef getMessage() const;
3333 SourceLineInfo getSourceInfo() const;
3334 StringRef getTestMacroName() const;
3335
3336 //protected:
3337 AssertionInfo m_info;
3338 AssertionResultData m_resultData;
3339 };
3340
3341} // end namespace Catch
3342
3343#endif // CATCH_ASSERTION_RESULT_HPP_INCLUDED
3344
3345
3346#ifndef CATCH_CASE_SENSITIVE_HPP_INCLUDED
3347#define CATCH_CASE_SENSITIVE_HPP_INCLUDED
3348
3349namespace Catch {
3350
3351 enum class CaseSensitive { Yes, No };
3352
3353} // namespace Catch
3354
3355#endif // CATCH_CASE_SENSITIVE_HPP_INCLUDED
3356
3357
3358#ifndef CATCH_CONFIG_HPP_INCLUDED
3359#define CATCH_CONFIG_HPP_INCLUDED
3360
3361
3362
3363#ifndef CATCH_TEST_SPEC_HPP_INCLUDED
3364#define CATCH_TEST_SPEC_HPP_INCLUDED
3365
3366#ifdef __clang__
3367#pragma clang diagnostic push
3368#pragma clang diagnostic ignored "-Wpadded"
3369#endif
3370
3371
3372
3373#ifndef CATCH_WILDCARD_PATTERN_HPP_INCLUDED
3374#define CATCH_WILDCARD_PATTERN_HPP_INCLUDED
3375
3376
3377#include <string>
3378
3379namespace Catch
3380{
3381 class WildcardPattern {
3382 enum WildcardPosition {
3383 NoWildcard = 0,
3384 WildcardAtStart = 1,
3385 WildcardAtEnd = 2,
3386 WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
3387 };
3388
3389 public:
3390
3391 WildcardPattern( std::string const& pattern, CaseSensitive caseSensitivity );
3392 bool matches( std::string const& str ) const;
3393
3394 private:
3395 std::string normaliseString( std::string const& str ) const;
3396 CaseSensitive m_caseSensitivity;
3397 WildcardPosition m_wildcard = NoWildcard;
3398 std::string m_pattern;
3399 };
3400}
3401
3402#endif // CATCH_WILDCARD_PATTERN_HPP_INCLUDED
3403
3404#include <iosfwd>
3405#include <string>
3406#include <vector>
3407
3408namespace Catch {
3409
3410 class IConfig;
3411 struct TestCaseInfo;
3412 class TestCaseHandle;
3413
3414 class TestSpec {
3415
3416 class Pattern {
3417 public:
3418 explicit Pattern( std::string const& name );
3419 virtual ~Pattern();
3420 virtual bool matches( TestCaseInfo const& testCase ) const = 0;
3421 std::string const& name() const;
3422 private:
3423 virtual void serializeTo( std::ostream& out ) const = 0;
3424 // Writes string that would be reparsed into the pattern
3425 friend std::ostream& operator<<(std::ostream& out,
3426 Pattern const& pattern) {
3427 pattern.serializeTo( out );
3428 return out;
3429 }
3430
3431 std::string const m_name;
3432 };
3433
3434 class NamePattern : public Pattern {
3435 public:
3436 explicit NamePattern( std::string const& name, std::string const& filterString );
3437 bool matches( TestCaseInfo const& testCase ) const override;
3438 private:
3439 void serializeTo( std::ostream& out ) const override;
3440
3441 WildcardPattern m_wildcardPattern;
3442 };
3443
3444 class TagPattern : public Pattern {
3445 public:
3446 explicit TagPattern( std::string const& tag, std::string const& filterString );
3447 bool matches( TestCaseInfo const& testCase ) const override;
3448 private:
3449 void serializeTo( std::ostream& out ) const override;
3450
3451 std::string m_tag;
3452 };
3453
3454 struct Filter {
3455 std::vector<Detail::unique_ptr<Pattern>> m_required;
3456 std::vector<Detail::unique_ptr<Pattern>> m_forbidden;
3457
3458 //! Serializes this filter into a string that would be parsed into
3459 //! an equivalent filter
3460 void serializeTo( std::ostream& out ) const;
3461 friend std::ostream& operator<<(std::ostream& out, Filter const& f) {
3462 f.serializeTo( out );
3463 return out;
3464 }
3465
3466 bool matches( TestCaseInfo const& testCase ) const;
3467 };
3468
3469 static std::string extractFilterName( Filter const& filter );
3470
3471 public:
3472 struct FilterMatch {
3473 std::string name;
3474 std::vector<TestCaseHandle const*> tests;
3475 };
3476 using Matches = std::vector<FilterMatch>;
3477 using vectorStrings = std::vector<std::string>;
3478
3479 bool hasFilters() const;
3480 bool matches( TestCaseInfo const& testCase ) const;
3481 Matches matchesByFilter( std::vector<TestCaseHandle> const& testCases, IConfig const& config ) const;
3482 const vectorStrings & getInvalidSpecs() const;
3483
3484 private:
3485 std::vector<Filter> m_filters;
3486 std::vector<std::string> m_invalidSpecs;
3487
3488 friend class TestSpecParser;
3489 //! Serializes this test spec into a string that would be parsed into
3490 //! equivalent test spec
3491 void serializeTo( std::ostream& out ) const;
3492 friend std::ostream& operator<<(std::ostream& out,
3493 TestSpec const& spec) {
3494 spec.serializeTo( out );
3495 return out;
3496 }
3497 };
3498}
3499
3500#ifdef __clang__
3501#pragma clang diagnostic pop
3502#endif
3503
3504#endif // CATCH_TEST_SPEC_HPP_INCLUDED
3505
3506
3507#ifndef CATCH_OPTIONAL_HPP_INCLUDED
3508#define CATCH_OPTIONAL_HPP_INCLUDED
3509
3510
3511#include <cassert>
3512
3513namespace Catch {
3514
3515 // An optional type
3516 template<typename T>
3517 class Optional {
3518 public:
3519 Optional(): nullableValue( nullptr ) {}
3520 ~Optional() { reset(); }
3521
3522 Optional( T const& _value ):
3523 nullableValue( new ( storage ) T( _value ) ) {}
3524 Optional( T&& _value ):
3525 nullableValue( new ( storage ) T( CATCH_MOVE( _value ) ) ) {}
3526
3527 Optional& operator=( T const& _value ) {
3528 reset();
3529 nullableValue = new ( storage ) T( _value );
3530 return *this;
3531 }
3532 Optional& operator=( T&& _value ) {
3533 reset();
3534 nullableValue = new ( storage ) T( CATCH_MOVE( _value ) );
3535 return *this;
3536 }
3537
3538 Optional( Optional const& _other ):
3539 nullableValue( _other ? new ( storage ) T( *_other ) : nullptr ) {}
3540 Optional( Optional&& _other ):
3541 nullableValue( _other ? new ( storage ) T( CATCH_MOVE( *_other ) )
3542 : nullptr ) {}
3543
3544 Optional& operator=( Optional const& _other ) {
3545 if ( &_other != this ) {
3546 reset();
3547 if ( _other ) { nullableValue = new ( storage ) T( *_other ); }
3548 }
3549 return *this;
3550 }
3551 Optional& operator=( Optional&& _other ) {
3552 if ( &_other != this ) {
3553 reset();
3554 if ( _other ) {
3555 nullableValue = new ( storage ) T( CATCH_MOVE( *_other ) );
3556 }
3557 }
3558 return *this;
3559 }
3560
3561 void reset() {
3562 if ( nullableValue ) { nullableValue->~T(); }
3563 nullableValue = nullptr;
3564 }
3565
3566 T& operator*() {
3567 assert(nullableValue);
3568 return *nullableValue;
3569 }
3570 T const& operator*() const {
3571 assert(nullableValue);
3572 return *nullableValue;
3573 }
3574 T* operator->() {
3575 assert(nullableValue);
3576 return nullableValue;
3577 }
3578 const T* operator->() const {
3579 assert(nullableValue);
3580 return nullableValue;
3581 }
3582
3583 T valueOr( T const& defaultValue ) const {
3584 return nullableValue ? *nullableValue : defaultValue;
3585 }
3586
3587 bool some() const { return nullableValue != nullptr; }
3588 bool none() const { return nullableValue == nullptr; }
3589
3590 bool operator !() const { return nullableValue == nullptr; }
3591 explicit operator bool() const {
3592 return some();
3593 }
3594
3595 friend bool operator==(Optional const& a, Optional const& b) {
3596 if (a.none() && b.none()) {
3597 return true;
3598 } else if (a.some() && b.some()) {
3599 return *a == *b;
3600 } else {
3601 return false;
3602 }
3603 }
3604 friend bool operator!=(Optional const& a, Optional const& b) {
3605 return !( a == b );
3606 }
3607
3608 private:
3609 T* nullableValue;
3610 alignas(alignof(T)) char storage[sizeof(T)];
3611 };
3612
3613} // end namespace Catch
3614
3615#endif // CATCH_OPTIONAL_HPP_INCLUDED
3616
3617
3618#ifndef CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
3619#define CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
3620
3621#include <cstdint>
3622
3623namespace Catch {
3624
3625 enum class GenerateFrom {
3626 Time,
3627 RandomDevice,
3628 //! Currently equivalent to RandomDevice, but can change at any point
3629 Default
3630 };
3631
3632 std::uint32_t generateRandomSeed(GenerateFrom from);
3633
3634} // end namespace Catch
3635
3636#endif // CATCH_RANDOM_SEED_GENERATION_HPP_INCLUDED
3637
3638
3639#ifndef CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
3640#define CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
3641
3642
3643#include <map>
3644#include <string>
3645#include <vector>
3646
3647namespace Catch {
3648
3649 enum class ColourMode : std::uint8_t;
3650
3651 namespace Detail {
3652 //! Splits the reporter spec into reporter name and kv-pair options
3653 std::vector<std::string> splitReporterSpec( StringRef reporterSpec );
3654
3655 Optional<ColourMode> stringToColourMode( StringRef colourMode );
3656 }
3657
3658 /**
3659 * Structured reporter spec that a reporter can be created from
3660 *
3661 * Parsing has been validated, but semantics have not. This means e.g.
3662 * that the colour mode is known to Catch2, but it might not be
3663 * compiled into the binary, and the output filename might not be
3664 * openable.
3665 */
3666 class ReporterSpec {
3667 std::string m_name;
3668 Optional<std::string> m_outputFileName;
3669 Optional<ColourMode> m_colourMode;
3670 std::map<std::string, std::string> m_customOptions;
3671
3672 friend bool operator==( ReporterSpec const& lhs,
3673 ReporterSpec const& rhs );
3674 friend bool operator!=( ReporterSpec const& lhs,
3675 ReporterSpec const& rhs ) {
3676 return !( lhs == rhs );
3677 }
3678
3679 public:
3680 ReporterSpec(
3681 std::string name,
3682 Optional<std::string> outputFileName,
3683 Optional<ColourMode> colourMode,
3684 std::map<std::string, std::string> customOptions );
3685
3686 std::string const& name() const { return m_name; }
3687
3688 Optional<std::string> const& outputFile() const {
3689 return m_outputFileName;
3690 }
3691
3692 Optional<ColourMode> const& colourMode() const { return m_colourMode; }
3693
3694 std::map<std::string, std::string> const& customOptions() const {
3695 return m_customOptions;
3696 }
3697 };
3698
3699 /**
3700 * Parses provided reporter spec string into
3701 *
3702 * Returns empty optional on errors, e.g.
3703 * * field that is not first and not a key+value pair
3704 * * duplicated keys in kv pair
3705 * * unknown catch reporter option
3706 * * empty key/value in an custom kv pair
3707 * * ...
3708 */
3709 Optional<ReporterSpec> parseReporterSpec( StringRef reporterSpec );
3710
3711}
3712
3713#endif // CATCH_REPORTER_SPEC_PARSER_HPP_INCLUDED
3714
3715#include <chrono>
3716#include <map>
3717#include <string>
3718#include <vector>
3719
3720namespace Catch {
3721
3722 class IStream;
3723
3724 /**
3725 * `ReporterSpec` but with the defaults filled in.
3726 *
3727 * Like `ReporterSpec`, the semantics are unchecked.
3728 */
3729 struct ProcessedReporterSpec {
3730 std::string name;
3731 std::string outputFilename;
3732 ColourMode colourMode;
3733 std::map<std::string, std::string> customOptions;
3734 friend bool operator==( ProcessedReporterSpec const& lhs,
3735 ProcessedReporterSpec const& rhs );
3736 friend bool operator!=( ProcessedReporterSpec const& lhs,
3737 ProcessedReporterSpec const& rhs ) {
3738 return !( lhs == rhs );
3739 }
3740 };
3741
3742 struct ConfigData {
3743
3744 bool listTests = false;
3745 bool listTags = false;
3746 bool listReporters = false;
3747 bool listListeners = false;
3748
3749 bool showSuccessfulTests = false;
3750 bool shouldDebugBreak = false;
3751 bool noThrow = false;
3752 bool showHelp = false;
3753 bool showInvisibles = false;
3754 bool filenamesAsTags = false;
3755 bool libIdentify = false;
3756 bool allowZeroTests = false;
3757
3758 int abortAfter = -1;
3759 uint32_t rngSeed = generateRandomSeed(GenerateFrom::Default);
3760
3761 unsigned int shardCount = 1;
3762 unsigned int shardIndex = 0;
3763
3764 bool skipBenchmarks = false;
3765 bool benchmarkNoAnalysis = false;
3766 unsigned int benchmarkSamples = 100;
3767 double benchmarkConfidenceInterval = 0.95;
3768 unsigned int benchmarkResamples = 100'000;
3769 std::chrono::milliseconds::rep benchmarkWarmupTime = 100;
3770
3771 Verbosity verbosity = Verbosity::Normal;
3772 WarnAbout::What warnings = WarnAbout::Nothing;
3773 ShowDurations showDurations = ShowDurations::DefaultForReporter;
3774 double minDuration = -1;
3775 TestRunOrder runOrder = TestRunOrder::Declared;
3776 ColourMode defaultColourMode = ColourMode::PlatformDefault;
3777 WaitForKeypress::When waitForKeypress = WaitForKeypress::Never;
3778
3779 std::string defaultOutputFilename;
3780 std::string name;
3781 std::string processName;
3782 std::vector<ReporterSpec> reporterSpecifications;
3783
3784 std::vector<std::string> testsOrTags;
3785 std::vector<std::string> sectionsToRun;
3786 };
3787
3788
3789 class Config : public IConfig {
3790 public:
3791
3792 Config() = default;
3793 Config( ConfigData const& data );
3794 ~Config() override; // = default in the cpp file
3795
3796 bool listTests() const;
3797 bool listTags() const;
3798 bool listReporters() const;
3799 bool listListeners() const;
3800
3801 std::vector<ReporterSpec> const& getReporterSpecs() const;
3802 std::vector<ProcessedReporterSpec> const&
3803 getProcessedReporterSpecs() const;
3804
3805 std::vector<std::string> const& getTestsOrTags() const override;
3806 std::vector<std::string> const& getSectionsToRun() const override;
3807
3808 TestSpec const& testSpec() const override;
3809 bool hasTestFilters() const override;
3810
3811 bool showHelp() const;
3812
3813 // IConfig interface
3814 bool allowThrows() const override;
3815 StringRef name() const override;
3816 bool includeSuccessfulResults() const override;
3817 bool warnAboutMissingAssertions() const override;
3818 bool warnAboutUnmatchedTestSpecs() const override;
3819 bool zeroTestsCountAsSuccess() const override;
3820 ShowDurations showDurations() const override;
3821 double minDuration() const override;
3822 TestRunOrder runOrder() const override;
3823 uint32_t rngSeed() const override;
3824 unsigned int shardCount() const override;
3825 unsigned int shardIndex() const override;
3826 ColourMode defaultColourMode() const override;
3827 bool shouldDebugBreak() const override;
3828 int abortAfter() const override;
3829 bool showInvisibles() const override;
3830 Verbosity verbosity() const override;
3831 bool skipBenchmarks() const override;
3832 bool benchmarkNoAnalysis() const override;
3833 unsigned int benchmarkSamples() const override;
3834 double benchmarkConfidenceInterval() const override;
3835 unsigned int benchmarkResamples() const override;
3836 std::chrono::milliseconds benchmarkWarmupTime() const override;
3837
3838 private:
3839 // Reads Bazel env vars and applies them to the config
3840 void readBazelEnvVars();
3841
3842 ConfigData m_data;
3843 std::vector<ProcessedReporterSpec> m_processedReporterSpecs;
3844 TestSpec m_testSpec;
3845 bool m_hasTestFilters = false;
3846 };
3847} // end namespace Catch
3848
3849#endif // CATCH_CONFIG_HPP_INCLUDED
3850
3851
3852#ifndef CATCH_GET_RANDOM_SEED_HPP_INCLUDED
3853#define CATCH_GET_RANDOM_SEED_HPP_INCLUDED
3854
3855#include <cstdint>
3856
3857namespace Catch {
3858 //! Returns Catch2's current RNG seed.
3859 std::uint32_t getSeed();
3860}
3861
3862#endif // CATCH_GET_RANDOM_SEED_HPP_INCLUDED
3863
3864
3865#ifndef CATCH_MESSAGE_HPP_INCLUDED
3866#define CATCH_MESSAGE_HPP_INCLUDED
3867
3868
3869
3870
3871/** \file
3872 * Wrapper for the CATCH_CONFIG_PREFIX_MESSAGES configuration option
3873 *
3874 * CATCH_CONFIG_PREFIX_ALL can be used to avoid clashes with other macros
3875 * by prepending CATCH_. This may not be desirable if the only clashes are with
3876 * logger macros such as INFO and WARN. In this cases
3877 * CATCH_CONFIG_PREFIX_MESSAGES can be used to only prefix a small subset
3878 * of relevant macros.
3879 *
3880 */
3881
3882#ifndef CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
3883#define CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
3884
3885
3886#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_PREFIX_MESSAGES)
3887 #define CATCH_CONFIG_PREFIX_MESSAGES
3888#endif
3889
3890#endif // CATCH_CONFIG_PREFIX_MESSAGES_HPP_INCLUDED
3891
3892
3893#ifndef CATCH_STREAM_END_STOP_HPP_INCLUDED
3894#define CATCH_STREAM_END_STOP_HPP_INCLUDED
3895
3896
3897namespace Catch {
3898
3899 // Use this in variadic streaming macros to allow
3900 // << +StreamEndStop
3901 // as well as
3902 // << stuff +StreamEndStop
3903 struct StreamEndStop {
3904 constexpr StringRef operator+() const { return StringRef(); }
3905
3906 template <typename T>
3907 constexpr friend T const& operator+( T const& value, StreamEndStop ) {
3908 return value;
3909 }
3910 };
3911
3912} // namespace Catch
3913
3914#endif // CATCH_STREAM_END_STOP_HPP_INCLUDED
3915
3916
3917#ifndef CATCH_MESSAGE_INFO_HPP_INCLUDED
3918#define CATCH_MESSAGE_INFO_HPP_INCLUDED
3919
3920
3921#include <string>
3922
3923namespace Catch {
3924
3925 struct MessageInfo {
3926 MessageInfo( StringRef _macroName,
3927 SourceLineInfo const& _lineInfo,
3928 ResultWas::OfType _type );
3929
3930 StringRef macroName;
3931 std::string message;
3932 SourceLineInfo lineInfo;
3933 ResultWas::OfType type;
3934 unsigned int sequence;
3935
3936 bool operator == (MessageInfo const& other) const {
3937 return sequence == other.sequence;
3938 }
3939 bool operator < (MessageInfo const& other) const {
3940 return sequence < other.sequence;
3941 }
3942 private:
3943 static unsigned int globalCount;
3944 };
3945
3946} // end namespace Catch
3947
3948#endif // CATCH_MESSAGE_INFO_HPP_INCLUDED
3949
3950#include <string>
3951#include <vector>
3952
3953namespace Catch {
3954
3955 struct SourceLineInfo;
3956 class IResultCapture;
3957
3958 struct MessageStream {
3959
3960 template<typename T>
3961 MessageStream& operator << ( T const& value ) {
3962 m_stream << value;
3963 return *this;
3964 }
3965
3966 ReusableStringStream m_stream;
3967 };
3968
3969 struct MessageBuilder : MessageStream {
3970 MessageBuilder( StringRef macroName,
3971 SourceLineInfo const& lineInfo,
3972 ResultWas::OfType type ):
3973 m_info(macroName, lineInfo, type) {}
3974
3975 template<typename T>
3976 MessageBuilder&& operator << ( T const& value ) && {
3977 m_stream << value;
3978 return CATCH_MOVE(*this);
3979 }
3980
3981 MessageInfo m_info;
3982 };
3983
3984 class ScopedMessage {
3985 public:
3986 explicit ScopedMessage( MessageBuilder&& builder );
3987 ScopedMessage( ScopedMessage& duplicate ) = delete;
3988 ScopedMessage( ScopedMessage&& old ) noexcept;
3989 ~ScopedMessage();
3990
3991 MessageInfo m_info;
3992 bool m_moved = false;
3993 };
3994
3995 class Capturer {
3996 std::vector<MessageInfo> m_messages;
3997 IResultCapture& m_resultCapture;
3998 size_t m_captured = 0;
3999 public:
4000 Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names );
4001
4002 Capturer(Capturer const&) = delete;
4003 Capturer& operator=(Capturer const&) = delete;
4004
4005 ~Capturer();
4006
4007 void captureValue( size_t index, std::string const& value );
4008
4009 template<typename T>
4010 void captureValues( size_t index, T const& value ) {
4011 captureValue( index, Catch::Detail::stringify( value ) );
4012 }
4013
4014 template<typename T, typename... Ts>
4015 void captureValues( size_t index, T const& value, Ts const&... values ) {
4016 captureValue( index, Catch::Detail::stringify(value) );
4017 captureValues( index+1, values... );
4018 }
4019 };
4020
4021} // end namespace Catch
4022
4023///////////////////////////////////////////////////////////////////////////////
4024#define INTERNAL_CATCH_MSG( macroName, messageType, resultDisposition, ... ) \
4025 do { \
4026 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::StringRef(), resultDisposition ); \
4027 catchAssertionHandler.handleMessage( messageType, ( Catch::MessageStream() << __VA_ARGS__ + ::Catch::StreamEndStop() ).m_stream.str() ); \
4028 catchAssertionHandler.complete(); \
4029 } while( false )
4030
4031///////////////////////////////////////////////////////////////////////////////
4032#define INTERNAL_CATCH_CAPTURE( varName, macroName, ... ) \
4033 Catch::Capturer varName( macroName##_catch_sr, \
4034 CATCH_INTERNAL_LINEINFO, \
4035 Catch::ResultWas::Info, \
4036 #__VA_ARGS__##_catch_sr ); \
4037 varName.captureValues( 0, __VA_ARGS__ )
4038
4039///////////////////////////////////////////////////////////////////////////////
4040#define INTERNAL_CATCH_INFO( macroName, log ) \
4041 const Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage )( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
4042
4043///////////////////////////////////////////////////////////////////////////////
4044#define INTERNAL_CATCH_UNSCOPED_INFO( macroName, log ) \
4045 Catch::getResultCapture().emplaceUnscopedMessage( Catch::MessageBuilder( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log )
4046
4047
4048#if defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
4049
4050 #define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( "CATCH_INFO", msg )
4051 #define CATCH_UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "CATCH_UNSCOPED_INFO", msg )
4052 #define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( "CATCH_WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
4053 #define CATCH_CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CATCH_CAPTURE", __VA_ARGS__ )
4054
4055#elif defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
4056
4057 #define CATCH_INFO( msg ) (void)(0)
4058 #define CATCH_UNSCOPED_INFO( msg ) (void)(0)
4059 #define CATCH_WARN( msg ) (void)(0)
4060 #define CATCH_CAPTURE( ... ) (void)(0)
4061
4062#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && !defined(CATCH_CONFIG_DISABLE)
4063
4064 #define INFO( msg ) INTERNAL_CATCH_INFO( "INFO", msg )
4065 #define UNSCOPED_INFO( msg ) INTERNAL_CATCH_UNSCOPED_INFO( "UNSCOPED_INFO", msg )
4066 #define WARN( msg ) INTERNAL_CATCH_MSG( "WARN", Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, msg )
4067 #define CAPTURE( ... ) INTERNAL_CATCH_CAPTURE( INTERNAL_CATCH_UNIQUE_NAME(capturer), "CAPTURE", __VA_ARGS__ )
4068
4069#elif !defined(CATCH_CONFIG_PREFIX_MESSAGES) && defined(CATCH_CONFIG_DISABLE)
4070
4071 #define INFO( msg ) (void)(0)
4072 #define UNSCOPED_INFO( msg ) (void)(0)
4073 #define WARN( msg ) (void)(0)
4074 #define CAPTURE( ... ) (void)(0)
4075
4076#endif // end of user facing macro declarations
4077
4078
4079
4080
4081#endif // CATCH_MESSAGE_HPP_INCLUDED
4082
4083
4084#ifndef CATCH_SECTION_INFO_HPP_INCLUDED
4085#define CATCH_SECTION_INFO_HPP_INCLUDED
4086
4087
4088
4089#ifndef CATCH_TOTALS_HPP_INCLUDED
4090#define CATCH_TOTALS_HPP_INCLUDED
4091
4092#include <cstdint>
4093
4094namespace Catch {
4095
4096 struct Counts {
4097 Counts operator - ( Counts const& other ) const;
4098 Counts& operator += ( Counts const& other );
4099
4100 std::uint64_t total() const;
4101 bool allPassed() const;
4102 bool allOk() const;
4103
4104 std::uint64_t passed = 0;
4105 std::uint64_t failed = 0;
4106 std::uint64_t failedButOk = 0;
4107 std::uint64_t skipped = 0;
4108 };
4109
4110 struct Totals {
4111
4112 Totals operator - ( Totals const& other ) const;
4113 Totals& operator += ( Totals const& other );
4114
4115 Totals delta( Totals const& prevTotals ) const;
4116
4117 Counts assertions;
4118 Counts testCases;
4119 };
4120}
4121
4122#endif // CATCH_TOTALS_HPP_INCLUDED
4123
4124#include <string>
4125
4126namespace Catch {
4127
4128 struct SectionInfo {
4129 // The last argument is ignored, so that people can write
4130 // SECTION("ShortName", "Proper description that is long") and
4131 // still use the `-c` flag comfortably.
4132 SectionInfo( SourceLineInfo const& _lineInfo, std::string _name,
4133 const char* const = nullptr ):
4134 name(CATCH_MOVE(_name)),
4135 lineInfo(_lineInfo)
4136 {}
4137
4138 std::string name;
4139 SourceLineInfo lineInfo;
4140 };
4141
4142 struct SectionEndInfo {
4143 SectionInfo sectionInfo;
4144 Counts prevAssertions;
4145 double durationInSeconds;
4146 };
4147
4148} // end namespace Catch
4149
4150#endif // CATCH_SECTION_INFO_HPP_INCLUDED
4151
4152
4153#ifndef CATCH_SESSION_HPP_INCLUDED
4154#define CATCH_SESSION_HPP_INCLUDED
4155
4156
4157
4158#ifndef CATCH_COMMANDLINE_HPP_INCLUDED
4159#define CATCH_COMMANDLINE_HPP_INCLUDED
4160
4161
4162
4163#ifndef CATCH_CLARA_HPP_INCLUDED
4164#define CATCH_CLARA_HPP_INCLUDED
4165
4166#if defined( __clang__ )
4167# pragma clang diagnostic push
4168# pragma clang diagnostic ignored "-Wweak-vtables"
4169# pragma clang diagnostic ignored "-Wshadow"
4170# pragma clang diagnostic ignored "-Wdeprecated"
4171#endif
4172
4173#if defined( __GNUC__ )
4174# pragma GCC diagnostic push
4175# pragma GCC diagnostic ignored "-Wsign-conversion"
4176#endif
4177
4178#ifndef CLARA_CONFIG_OPTIONAL_TYPE
4179# ifdef __has_include
4180# if __has_include( <optional>) && __cplusplus >= 201703L
4181# include <optional>
4182# define CLARA_CONFIG_OPTIONAL_TYPE std::optional
4183# endif
4184# endif
4185#endif
4186
4187
4188#include <cassert>
4189#include <memory>
4190#include <ostream>
4191#include <sstream>
4192#include <string>
4193#include <type_traits>
4194#include <vector>
4195
4196namespace Catch {
4197 namespace Clara {
4198
4199 class Args;
4200 class Parser;
4201
4202 // enum of result types from a parse
4203 enum class ParseResultType {
4204 Matched,
4205 NoMatch,
4206 ShortCircuitAll,
4207 ShortCircuitSame
4208 };
4209
4210 struct accept_many_t {};
4211 constexpr accept_many_t accept_many {};
4212
4213 namespace Detail {
4214 struct fake_arg {
4215 template <typename T>
4216 operator T();
4217 };
4218
4219 template <typename F, typename = void>
4220 struct is_unary_function : std::false_type {};
4221
4222 template <typename F>
4223 struct is_unary_function<
4224 F,
4225 Catch::Detail::void_t<decltype(
4226 std::declval<F>()( fake_arg() ) )
4227 >
4228 > : std::true_type {};
4229
4230 // Traits for extracting arg and return type of lambdas (for single
4231 // argument lambdas)
4232 template <typename L>
4233 struct UnaryLambdaTraits
4234 : UnaryLambdaTraits<decltype( &L::operator() )> {};
4235
4236 template <typename ClassT, typename ReturnT, typename... Args>
4237 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( Args... ) const> {
4238 static const bool isValid = false;
4239 };
4240
4241 template <typename ClassT, typename ReturnT, typename ArgT>
4242 struct UnaryLambdaTraits<ReturnT ( ClassT::* )( ArgT ) const> {
4243 static const bool isValid = true;
4244 using ArgType = std::remove_const_t<std::remove_reference_t<ArgT>>;
4245 using ReturnType = ReturnT;
4246 };
4247
4248 class TokenStream;
4249
4250 // Wraps a token coming from a token stream. These may not directly
4251 // correspond to strings as a single string may encode an option +
4252 // its argument if the : or = form is used
4253 enum class TokenType { Option, Argument };
4254 struct Token {
4255 TokenType type;
4256 StringRef token;
4257 };
4258
4259 // Abstracts iterators into args as a stream of tokens, with option
4260 // arguments uniformly handled
4261 class TokenStream {
4262 using Iterator = std::vector<StringRef>::const_iterator;
4263 Iterator it;
4264 Iterator itEnd;
4265 std::vector<Token> m_tokenBuffer;
4266 void loadBuffer();
4267
4268 public:
4269 explicit TokenStream( Args const& args );
4270 TokenStream( Iterator it, Iterator itEnd );
4271
4272 explicit operator bool() const {
4273 return !m_tokenBuffer.empty() || it != itEnd;
4274 }
4275
4276 size_t count() const {
4277 return m_tokenBuffer.size() + ( itEnd - it );
4278 }
4279
4280 Token operator*() const {
4281 assert( !m_tokenBuffer.empty() );
4282 return m_tokenBuffer.front();
4283 }
4284
4285 Token const* operator->() const {
4286 assert( !m_tokenBuffer.empty() );
4287 return &m_tokenBuffer.front();
4288 }
4289
4290 TokenStream& operator++();
4291 };
4292
4293 //! Denotes type of a parsing result
4294 enum class ResultType {
4295 Ok, ///< No errors
4296 LogicError, ///< Error in user-specified arguments for
4297 ///< construction
4298 RuntimeError ///< Error in parsing inputs
4299 };
4300
4301 class ResultBase {
4302 protected:
4303 ResultBase( ResultType type ): m_type( type ) {}
4304 virtual ~ResultBase(); // = default;
4305
4306
4307 ResultBase(ResultBase const&) = default;
4308 ResultBase& operator=(ResultBase const&) = default;
4309 ResultBase(ResultBase&&) = default;
4310 ResultBase& operator=(ResultBase&&) = default;
4311
4312 virtual void enforceOk() const = 0;
4313
4314 ResultType m_type;
4315 };
4316
4317 template <typename T>
4318 class ResultValueBase : public ResultBase {
4319 public:
4320 T const& value() const& {
4321 enforceOk();
4322 return m_value;
4323 }
4324 T&& value() && {
4325 enforceOk();
4326 return CATCH_MOVE( m_value );
4327 }
4328
4329 protected:
4330 ResultValueBase( ResultType type ): ResultBase( type ) {}
4331
4332 ResultValueBase( ResultValueBase const& other ):
4333 ResultBase( other ) {
4334 if ( m_type == ResultType::Ok )
4335 new ( &m_value ) T( other.m_value );
4336 }
4337 ResultValueBase( ResultValueBase&& other ):
4338 ResultBase( other ) {
4339 if ( m_type == ResultType::Ok )
4340 new ( &m_value ) T( CATCH_MOVE(other.m_value) );
4341 }
4342
4343
4344 ResultValueBase( ResultType, T const& value ):
4345 ResultBase( ResultType::Ok ) {
4346 new ( &m_value ) T( value );
4347 }
4348 ResultValueBase( ResultType, T&& value ):
4349 ResultBase( ResultType::Ok ) {
4350 new ( &m_value ) T( CATCH_MOVE(value) );
4351 }
4352
4353 ResultValueBase& operator=( ResultValueBase const& other ) {
4354 if ( m_type == ResultType::Ok )
4355 m_value.~T();
4356 ResultBase::operator=( other );
4357 if ( m_type == ResultType::Ok )
4358 new ( &m_value ) T( other.m_value );
4359 return *this;
4360 }
4361 ResultValueBase& operator=( ResultValueBase&& other ) {
4362 if ( m_type == ResultType::Ok ) m_value.~T();
4363 ResultBase::operator=( other );
4364 if ( m_type == ResultType::Ok )
4365 new ( &m_value ) T( CATCH_MOVE(other.m_value) );
4366 return *this;
4367 }
4368
4369
4370 ~ResultValueBase() override {
4371 if ( m_type == ResultType::Ok )
4372 m_value.~T();
4373 }
4374
4375 union {
4376 T m_value;
4377 };
4378 };
4379
4380 template <> class ResultValueBase<void> : public ResultBase {
4381 protected:
4382 using ResultBase::ResultBase;
4383 };
4384
4385 template <typename T = void>
4386 class BasicResult : public ResultValueBase<T> {
4387 public:
4388 template <typename U>
4389 explicit BasicResult( BasicResult<U> const& other ):
4390 ResultValueBase<T>( other.type() ),
4391 m_errorMessage( other.errorMessage() ) {
4392 assert( type() != ResultType::Ok );
4393 }
4394
4395 template <typename U>
4396 static auto ok( U&& value ) -> BasicResult {
4397 return { ResultType::Ok, CATCH_FORWARD(value) };
4398 }
4399 static auto ok() -> BasicResult { return { ResultType::Ok }; }
4400 static auto logicError( std::string&& message )
4401 -> BasicResult {
4402 return { ResultType::LogicError, CATCH_MOVE(message) };
4403 }
4404 static auto runtimeError( std::string&& message )
4405 -> BasicResult {
4406 return { ResultType::RuntimeError, CATCH_MOVE(message) };
4407 }
4408
4409 explicit operator bool() const {
4410 return m_type == ResultType::Ok;
4411 }
4412 auto type() const -> ResultType { return m_type; }
4413 auto errorMessage() const -> std::string const& {
4414 return m_errorMessage;
4415 }
4416
4417 protected:
4418 void enforceOk() const override {
4419
4420 // Errors shouldn't reach this point, but if they do
4421 // the actual error message will be in m_errorMessage
4422 assert( m_type != ResultType::LogicError );
4423 assert( m_type != ResultType::RuntimeError );
4424 if ( m_type != ResultType::Ok )
4425 std::abort();
4426 }
4427
4428 std::string
4429 m_errorMessage; // Only populated if resultType is an error
4430
4431 BasicResult( ResultType type,
4432 std::string&& message ):
4433 ResultValueBase<T>( type ), m_errorMessage( CATCH_MOVE(message) ) {
4434 assert( m_type != ResultType::Ok );
4435 }
4436
4437 using ResultValueBase<T>::ResultValueBase;
4438 using ResultBase::m_type;
4439 };
4440
4441 class ParseState {
4442 public:
4443 ParseState( ParseResultType type,
4444 TokenStream remainingTokens );
4445
4446 ParseResultType type() const { return m_type; }
4447 TokenStream const& remainingTokens() const& {
4448 return m_remainingTokens;
4449 }
4450 TokenStream&& remainingTokens() && {
4451 return CATCH_MOVE( m_remainingTokens );
4452 }
4453
4454 private:
4455 ParseResultType m_type;
4456 TokenStream m_remainingTokens;
4457 };
4458
4459 using Result = BasicResult<void>;
4460 using ParserResult = BasicResult<ParseResultType>;
4461 using InternalParseResult = BasicResult<ParseState>;
4462
4463 struct HelpColumns {
4464 std::string left;
4465 StringRef descriptions;
4466 };
4467
4468 template <typename T>
4469 ParserResult convertInto( std::string const& source, T& target ) {
4470 std::stringstream ss( source );
4471 ss >> target;
4472 if ( ss.fail() ) {
4473 return ParserResult::runtimeError(
4474 "Unable to convert '" + source +
4475 "' to destination type" );
4476 } else {
4477 return ParserResult::ok( ParseResultType::Matched );
4478 }
4479 }
4480 ParserResult convertInto( std::string const& source,
4481 std::string& target );
4482 ParserResult convertInto( std::string const& source, bool& target );
4483
4484#ifdef CLARA_CONFIG_OPTIONAL_TYPE
4485 template <typename T>
4486 auto convertInto( std::string const& source,
4487 CLARA_CONFIG_OPTIONAL_TYPE<T>& target )
4488 -> ParserResult {
4489 T temp;
4490 auto result = convertInto( source, temp );
4491 if ( result )
4492 target = CATCH_MOVE( temp );
4493 return result;
4494 }
4495#endif // CLARA_CONFIG_OPTIONAL_TYPE
4496
4497 struct BoundRef : Catch::Detail::NonCopyable {
4498 virtual ~BoundRef() = default;
4499 virtual bool isContainer() const;
4500 virtual bool isFlag() const;
4501 };
4502 struct BoundValueRefBase : BoundRef {
4503 virtual auto setValue( std::string const& arg )
4504 -> ParserResult = 0;
4505 };
4506 struct BoundFlagRefBase : BoundRef {
4507 virtual auto setFlag( bool flag ) -> ParserResult = 0;
4508 bool isFlag() const override;
4509 };
4510
4511 template <typename T> struct BoundValueRef : BoundValueRefBase {
4512 T& m_ref;
4513
4514 explicit BoundValueRef( T& ref ): m_ref( ref ) {}
4515
4516 ParserResult setValue( std::string const& arg ) override {
4517 return convertInto( arg, m_ref );
4518 }
4519 };
4520
4521 template <typename T>
4522 struct BoundValueRef<std::vector<T>> : BoundValueRefBase {
4523 std::vector<T>& m_ref;
4524
4525 explicit BoundValueRef( std::vector<T>& ref ): m_ref( ref ) {}
4526
4527 auto isContainer() const -> bool override { return true; }
4528
4529 auto setValue( std::string const& arg )
4530 -> ParserResult override {
4531 T temp;
4532 auto result = convertInto( arg, temp );
4533 if ( result )
4534 m_ref.push_back( temp );
4535 return result;
4536 }
4537 };
4538
4539 struct BoundFlagRef : BoundFlagRefBase {
4540 bool& m_ref;
4541
4542 explicit BoundFlagRef( bool& ref ): m_ref( ref ) {}
4543
4544 ParserResult setFlag( bool flag ) override;
4545 };
4546
4547 template <typename ReturnType> struct LambdaInvoker {
4548 static_assert(
4549 std::is_same<ReturnType, ParserResult>::value,
4550 "Lambda must return void or clara::ParserResult" );
4551
4552 template <typename L, typename ArgType>
4553 static auto invoke( L const& lambda, ArgType const& arg )
4554 -> ParserResult {
4555 return lambda( arg );
4556 }
4557 };
4558
4559 template <> struct LambdaInvoker<void> {
4560 template <typename L, typename ArgType>
4561 static auto invoke( L const& lambda, ArgType const& arg )
4562 -> ParserResult {
4563 lambda( arg );
4564 return ParserResult::ok( ParseResultType::Matched );
4565 }
4566 };
4567
4568 template <typename ArgType, typename L>
4569 auto invokeLambda( L const& lambda, std::string const& arg )
4570 -> ParserResult {
4571 ArgType temp{};
4572 auto result = convertInto( arg, temp );
4573 return !result ? result
4574 : LambdaInvoker<typename UnaryLambdaTraits<
4575 L>::ReturnType>::invoke( lambda, temp );
4576 }
4577
4578 template <typename L> struct BoundLambda : BoundValueRefBase {
4579 L m_lambda;
4580
4581 static_assert(
4582 UnaryLambdaTraits<L>::isValid,
4583 "Supplied lambda must take exactly one argument" );
4584 explicit BoundLambda( L const& lambda ): m_lambda( lambda ) {}
4585
4586 auto setValue( std::string const& arg )
4587 -> ParserResult override {
4588 return invokeLambda<typename UnaryLambdaTraits<L>::ArgType>(
4589 m_lambda, arg );
4590 }
4591 };
4592
4593 template <typename L> struct BoundManyLambda : BoundLambda<L> {
4594 explicit BoundManyLambda( L const& lambda ): BoundLambda<L>( lambda ) {}
4595 bool isContainer() const override { return true; }
4596 };
4597
4598 template <typename L> struct BoundFlagLambda : BoundFlagRefBase {
4599 L m_lambda;
4600
4601 static_assert(
4602 UnaryLambdaTraits<L>::isValid,
4603 "Supplied lambda must take exactly one argument" );
4604 static_assert(
4605 std::is_same<typename UnaryLambdaTraits<L>::ArgType,
4606 bool>::value,
4607 "flags must be boolean" );
4608
4609 explicit BoundFlagLambda( L const& lambda ):
4610 m_lambda( lambda ) {}
4611
4612 auto setFlag( bool flag ) -> ParserResult override {
4613 return LambdaInvoker<typename UnaryLambdaTraits<
4614 L>::ReturnType>::invoke( m_lambda, flag );
4615 }
4616 };
4617
4618 enum class Optionality { Optional, Required };
4619
4620 class ParserBase {
4621 public:
4622 virtual ~ParserBase() = default;
4623 virtual auto validate() const -> Result { return Result::ok(); }
4624 virtual auto parse( std::string const& exeName,
4625 TokenStream tokens ) const
4626 -> InternalParseResult = 0;
4627 virtual size_t cardinality() const;
4628
4629 InternalParseResult parse( Args const& args ) const;
4630 };
4631
4632 template <typename DerivedT>
4633 class ComposableParserImpl : public ParserBase {
4634 public:
4635 template <typename T>
4636 auto operator|( T const& other ) const -> Parser;
4637 };
4638
4639 // Common code and state for Args and Opts
4640 template <typename DerivedT>
4641 class ParserRefImpl : public ComposableParserImpl<DerivedT> {
4642 protected:
4643 Optionality m_optionality = Optionality::Optional;
4644 std::shared_ptr<BoundRef> m_ref;
4645 StringRef m_hint;
4646 StringRef m_description;
4647
4648 explicit ParserRefImpl( std::shared_ptr<BoundRef> const& ref ):
4649 m_ref( ref ) {}
4650
4651 public:
4652 template <typename LambdaT>
4653 ParserRefImpl( accept_many_t,
4654 LambdaT const& ref,
4655 StringRef hint ):
4656 m_ref( std::make_shared<BoundManyLambda<LambdaT>>( ref ) ),
4657 m_hint( hint ) {}
4658
4659 template <typename T,
4660 typename = typename std::enable_if_t<
4661 !Detail::is_unary_function<T>::value>>
4662 ParserRefImpl( T& ref, StringRef hint ):
4663 m_ref( std::make_shared<BoundValueRef<T>>( ref ) ),
4664 m_hint( hint ) {}
4665
4666 template <typename LambdaT,
4667 typename = typename std::enable_if_t<
4668 Detail::is_unary_function<LambdaT>::value>>
4669 ParserRefImpl( LambdaT const& ref, StringRef hint ):
4670 m_ref( std::make_shared<BoundLambda<LambdaT>>( ref ) ),
4671 m_hint( hint ) {}
4672
4673 DerivedT& operator()( StringRef description ) & {
4674 m_description = description;
4675 return static_cast<DerivedT&>( *this );
4676 }
4677 DerivedT&& operator()( StringRef description ) && {
4678 m_description = description;
4679 return static_cast<DerivedT&&>( *this );
4680 }
4681
4682 auto optional() -> DerivedT& {
4683 m_optionality = Optionality::Optional;
4684 return static_cast<DerivedT&>( *this );
4685 }
4686
4687 auto required() -> DerivedT& {
4688 m_optionality = Optionality::Required;
4689 return static_cast<DerivedT&>( *this );
4690 }
4691
4692 auto isOptional() const -> bool {
4693 return m_optionality == Optionality::Optional;
4694 }
4695
4696 auto cardinality() const -> size_t override {
4697 if ( m_ref->isContainer() )
4698 return 0;
4699 else
4700 return 1;
4701 }
4702
4703 StringRef hint() const { return m_hint; }
4704 };
4705
4706 } // namespace detail
4707
4708
4709 // A parser for arguments
4710 class Arg : public Detail::ParserRefImpl<Arg> {
4711 public:
4712 using ParserRefImpl::ParserRefImpl;
4713 using ParserBase::parse;
4714
4715 Detail::InternalParseResult
4716 parse(std::string const&,
4717 Detail::TokenStream tokens) const override;
4718 };
4719
4720 // A parser for options
4721 class Opt : public Detail::ParserRefImpl<Opt> {
4722 protected:
4723 std::vector<StringRef> m_optNames;
4724
4725 public:
4726 template <typename LambdaT>
4727 explicit Opt(LambdaT const& ref) :
4728 ParserRefImpl(
4729 std::make_shared<Detail::BoundFlagLambda<LambdaT>>(ref)) {}
4730
4731 explicit Opt(bool& ref);
4732
4733 template <typename LambdaT,
4734 typename = typename std::enable_if_t<
4735 Detail::is_unary_function<LambdaT>::value>>
4736 Opt( LambdaT const& ref, StringRef hint ):
4737 ParserRefImpl( ref, hint ) {}
4738
4739 template <typename LambdaT>
4740 Opt( accept_many_t, LambdaT const& ref, StringRef hint ):
4741 ParserRefImpl( accept_many, ref, hint ) {}
4742
4743 template <typename T,
4744 typename = typename std::enable_if_t<
4745 !Detail::is_unary_function<T>::value>>
4746 Opt( T& ref, StringRef hint ):
4747 ParserRefImpl( ref, hint ) {}
4748
4749 Opt& operator[]( StringRef optName ) & {
4750 m_optNames.push_back(optName);
4751 return *this;
4752 }
4753 Opt&& operator[]( StringRef optName ) && {
4754 m_optNames.push_back( optName );
4755 return CATCH_MOVE(*this);
4756 }
4757
4758 Detail::HelpColumns getHelpColumns() const;
4759
4760 bool isMatch(StringRef optToken) const;
4761
4762 using ParserBase::parse;
4763
4764 Detail::InternalParseResult
4765 parse(std::string const&,
4766 Detail::TokenStream tokens) const override;
4767
4768 Detail::Result validate() const override;
4769 };
4770
4771 // Specifies the name of the executable
4772 class ExeName : public Detail::ComposableParserImpl<ExeName> {
4773 std::shared_ptr<std::string> m_name;
4774 std::shared_ptr<Detail::BoundValueRefBase> m_ref;
4775
4776 public:
4777 ExeName();
4778 explicit ExeName(std::string& ref);
4779
4780 template <typename LambdaT>
4781 explicit ExeName(LambdaT const& lambda) : ExeName() {
4782 m_ref = std::make_shared<Detail::BoundLambda<LambdaT>>(lambda);
4783 }
4784
4785 // The exe name is not parsed out of the normal tokens, but is
4786 // handled specially
4787 Detail::InternalParseResult
4788 parse(std::string const&,
4789 Detail::TokenStream tokens) const override;
4790
4791 std::string const& name() const { return *m_name; }
4792 Detail::ParserResult set(std::string const& newName);
4793 };
4794
4795
4796 // A Combined parser
4797 class Parser : Detail::ParserBase {
4798 mutable ExeName m_exeName;
4799 std::vector<Opt> m_options;
4800 std::vector<Arg> m_args;
4801
4802 public:
4803
4804 auto operator|=(ExeName const& exeName) -> Parser& {
4805 m_exeName = exeName;
4806 return *this;
4807 }
4808
4809 auto operator|=(Arg const& arg) -> Parser& {
4810 m_args.push_back(arg);
4811 return *this;
4812 }
4813
4814 friend Parser& operator|=( Parser& p, Opt const& opt ) {
4815 p.m_options.push_back( opt );
4816 return p;
4817 }
4818 friend Parser& operator|=( Parser& p, Opt&& opt ) {
4819 p.m_options.push_back( CATCH_MOVE(opt) );
4820 return p;
4821 }
4822
4823 Parser& operator|=(Parser const& other);
4824
4825 template <typename T>
4826 friend Parser operator|( Parser const& p, T&& rhs ) {
4827 Parser temp( p );
4828 temp |= rhs;
4829 return temp;
4830 }
4831
4832 template <typename T>
4833 friend Parser operator|( Parser&& p, T&& rhs ) {
4834 p |= CATCH_FORWARD(rhs);
4835 return CATCH_MOVE(p);
4836 }
4837
4838 std::vector<Detail::HelpColumns> getHelpColumns() const;
4839
4840 void writeToStream(std::ostream& os) const;
4841
4842 friend auto operator<<(std::ostream& os, Parser const& parser)
4843 -> std::ostream& {
4844 parser.writeToStream(os);
4845 return os;
4846 }
4847
4848 Detail::Result validate() const override;
4849
4850 using ParserBase::parse;
4851 Detail::InternalParseResult
4852 parse(std::string const& exeName,
4853 Detail::TokenStream tokens) const override;
4854 };
4855
4856 /**
4857 * Wrapper over argc + argv, assumes that the inputs outlive it
4858 */
4859 class Args {
4860 friend Detail::TokenStream;
4861 StringRef m_exeName;
4862 std::vector<StringRef> m_args;
4863
4864 public:
4865 Args(int argc, char const* const* argv);
4866 // Helper constructor for testing
4867 Args(std::initializer_list<StringRef> args);
4868
4869 StringRef exeName() const { return m_exeName; }
4870 };
4871
4872
4873 // Convenience wrapper for option parser that specifies the help option
4874 struct Help : Opt {
4875 Help(bool& showHelpFlag);
4876 };
4877
4878 // Result type for parser operation
4879 using Detail::ParserResult;
4880
4881 namespace Detail {
4882 template <typename DerivedT>
4883 template <typename T>
4884 Parser
4885 ComposableParserImpl<DerivedT>::operator|(T const& other) const {
4886 return Parser() | static_cast<DerivedT const&>(*this) | other;
4887 }
4888 }
4889
4890 } // namespace Clara
4891} // namespace Catch
4892
4893#if defined( __clang__ )
4894# pragma clang diagnostic pop
4895#endif
4896
4897#if defined( __GNUC__ )
4898# pragma GCC diagnostic pop
4899#endif
4900
4901#endif // CATCH_CLARA_HPP_INCLUDED
4902
4903namespace Catch {
4904
4905 struct ConfigData;
4906
4907 Clara::Parser makeCommandLineParser( ConfigData& config );
4908
4909} // end namespace Catch
4910
4911#endif // CATCH_COMMANDLINE_HPP_INCLUDED
4912
4913namespace Catch {
4914
4915 class Session : Detail::NonCopyable {
4916 public:
4917
4918 Session();
4919 ~Session();
4920
4921 void showHelp() const;
4922 void libIdentify();
4923
4924 int applyCommandLine( int argc, char const * const * argv );
4925 #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
4926 int applyCommandLine( int argc, wchar_t const * const * argv );
4927 #endif
4928
4929 void useConfigData( ConfigData const& configData );
4930
4931 template<typename CharT>
4932 int run(int argc, CharT const * const argv[]) {
4933 if (m_startupExceptions)
4934 return 1;
4935 int returnCode = applyCommandLine(argc, argv);
4936 if (returnCode == 0)
4937 returnCode = run();
4938 return returnCode;
4939 }
4940
4941 int run();
4942
4943 Clara::Parser const& cli() const;
4944 void cli( Clara::Parser const& newParser );
4945 ConfigData& configData();
4946 Config& config();
4947 private:
4948 int runInternal();
4949
4950 Clara::Parser m_cli;
4951 ConfigData m_configData;
4952 Detail::unique_ptr<Config> m_config;
4953 bool m_startupExceptions = false;
4954 };
4955
4956} // end namespace Catch
4957
4958#endif // CATCH_SESSION_HPP_INCLUDED
4959
4960
4961#ifndef CATCH_TAG_ALIAS_HPP_INCLUDED
4962#define CATCH_TAG_ALIAS_HPP_INCLUDED
4963
4964
4965#include <string>
4966
4967namespace Catch {
4968
4969 struct TagAlias {
4970 TagAlias(std::string const& _tag, SourceLineInfo _lineInfo):
4971 tag(_tag),
4972 lineInfo(_lineInfo)
4973 {}
4974
4975 std::string tag;
4976 SourceLineInfo lineInfo;
4977 };
4978
4979} // end namespace Catch
4980
4981#endif // CATCH_TAG_ALIAS_HPP_INCLUDED
4982
4983
4984#ifndef CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
4985#define CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
4986
4987
4988namespace Catch {
4989
4990 struct RegistrarForTagAliases {
4991 RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
4992 };
4993
4994} // end namespace Catch
4995
4996#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \
4997 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
4998 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
4999 namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \
5000 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5001
5002#endif // CATCH_TAG_ALIAS_AUTOREGISTRAR_HPP_INCLUDED
5003
5004
5005#ifndef CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
5006#define CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
5007
5008// We need this suppression to leak, because it took until GCC 10
5009// for the front end to handle local suppression via _Pragma properly
5010// inside templates (so `TEMPLATE_TEST_CASE` and co).
5011// **THIS IS DIFFERENT FOR STANDARD TESTS, WHERE GCC 9 IS SUFFICIENT**
5012#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ < 10
5013#pragma GCC diagnostic ignored "-Wparentheses"
5014#endif
5015
5016
5017
5018
5019#ifndef CATCH_TEST_MACROS_HPP_INCLUDED
5020#define CATCH_TEST_MACROS_HPP_INCLUDED
5021
5022
5023
5024#ifndef CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
5025#define CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
5026
5027
5028
5029#ifndef CATCH_ASSERTION_HANDLER_HPP_INCLUDED
5030#define CATCH_ASSERTION_HANDLER_HPP_INCLUDED
5031
5032
5033
5034#ifndef CATCH_DECOMPOSER_HPP_INCLUDED
5035#define CATCH_DECOMPOSER_HPP_INCLUDED
5036
5037
5038
5039#ifndef CATCH_COMPARE_TRAITS_HPP_INCLUDED
5040#define CATCH_COMPARE_TRAITS_HPP_INCLUDED
5041
5042
5043#include <type_traits>
5044
5045namespace Catch {
5046 namespace Detail {
5047
5048#if defined( __GNUC__ ) && !defined( __clang__ )
5049# pragma GCC diagnostic push
5050 // GCC likes to complain about comparing bool with 0, in the decltype()
5051 // that defines the comparable traits below.
5052# pragma GCC diagnostic ignored "-Wbool-compare"
5053 // "ordered comparison of pointer with integer zero" same as above,
5054 // but it does not have a separate warning flag to suppress
5055# pragma GCC diagnostic ignored "-Wextra"
5056 // Did you know that comparing floats with `0` directly
5057 // is super-duper dangerous in unevaluated context?
5058# pragma GCC diagnostic ignored "-Wfloat-equal"
5059#endif
5060
5061#if defined( __clang__ )
5062# pragma clang diagnostic push
5063 // Did you know that comparing floats with `0` directly
5064 // is super-duper dangerous in unevaluated context?
5065# pragma clang diagnostic ignored "-Wfloat-equal"
5066#endif
5067
5068#define CATCH_DEFINE_COMPARABLE_TRAIT( id, op ) \
5069 template <typename, typename, typename = void> \
5070 struct is_##id##_comparable : std::false_type {}; \
5071 template <typename T, typename U> \
5072 struct is_##id##_comparable< \
5073 T, \
5074 U, \
5075 void_t<decltype( std::declval<T>() op std::declval<U>() )>> \
5076 : std::true_type {}; \
5077 template <typename, typename = void> \
5078 struct is_##id##_0_comparable : std::false_type {}; \
5079 template <typename T> \
5080 struct is_##id##_0_comparable<T, \
5081 void_t<decltype( std::declval<T>() op 0 )>> \
5082 : std::true_type {};
5083
5084 // We need all 6 pre-spaceship comparison ops: <, <=, >, >=, ==, !=
5085 CATCH_DEFINE_COMPARABLE_TRAIT( lt, < )
5086 CATCH_DEFINE_COMPARABLE_TRAIT( le, <= )
5087 CATCH_DEFINE_COMPARABLE_TRAIT( gt, > )
5088 CATCH_DEFINE_COMPARABLE_TRAIT( ge, >= )
5089 CATCH_DEFINE_COMPARABLE_TRAIT( eq, == )
5090 CATCH_DEFINE_COMPARABLE_TRAIT( ne, != )
5091
5092#undef CATCH_DEFINE_COMPARABLE_TRAIT
5093
5094#if defined( __GNUC__ ) && !defined( __clang__ )
5095# pragma GCC diagnostic pop
5096#endif
5097#if defined( __clang__ )
5098# pragma clang diagnostic pop
5099#endif
5100
5101
5102 } // namespace Detail
5103} // namespace Catch
5104
5105#endif // CATCH_COMPARE_TRAITS_HPP_INCLUDED
5106
5107
5108#ifndef CATCH_LOGICAL_TRAITS_HPP_INCLUDED
5109#define CATCH_LOGICAL_TRAITS_HPP_INCLUDED
5110
5111#include <type_traits>
5112
5113namespace Catch {
5114namespace Detail {
5115
5116#if defined( __cpp_lib_logical_traits ) && __cpp_lib_logical_traits >= 201510
5117
5118 using std::conjunction;
5119 using std::disjunction;
5120 using std::negation;
5121
5122#else
5123
5124 template <class...> struct conjunction : std::true_type {};
5125 template <class B1> struct conjunction<B1> : B1 {};
5126 template <class B1, class... Bn>
5127 struct conjunction<B1, Bn...>
5128 : std::conditional_t<bool( B1::value ), conjunction<Bn...>, B1> {};
5129
5130 template <class...> struct disjunction : std::false_type {};
5131 template <class B1> struct disjunction<B1> : B1 {};
5132 template <class B1, class... Bn>
5133 struct disjunction<B1, Bn...>
5134 : std::conditional_t<bool( B1::value ), B1, disjunction<Bn...>> {};
5135
5136 template <class B>
5137 struct negation : std::integral_constant<bool, !bool(B::value)> {};
5138
5139#endif
5140
5141} // namespace Detail
5142} // namespace Catch
5143
5144#endif // CATCH_LOGICAL_TRAITS_HPP_INCLUDED
5145
5146#include <type_traits>
5147#include <iosfwd>
5148
5149/** \file
5150 * Why does decomposing look the way it does:
5151 *
5152 * Conceptually, decomposing is simple. We change `REQUIRE( a == b )` into
5153 * `Decomposer{} <= a == b`, so that `Decomposer{} <= a` is evaluated first,
5154 * and our custom operator is used for `a == b`, because `a` is transformed
5155 * into `ExprLhs<T&>` and then into `BinaryExpr<T&, U&>`.
5156 *
5157 * In practice, decomposing ends up a mess, because we have to support
5158 * various fun things.
5159 *
5160 * 1) Types that are only comparable with literal 0, and they do this by
5161 * comparing against a magic type with pointer constructor and deleted
5162 * other constructors. Example: `REQUIRE((a <=> b) == 0)` in libstdc++
5163 *
5164 * 2) Types that are only comparable with literal 0, and they do this by
5165 * comparing against a magic type with consteval integer constructor.
5166 * Example: `REQUIRE((a <=> b) == 0)` in current MSVC STL.
5167 *
5168 * 3) Types that have no linkage, and so we cannot form a reference to
5169 * them. Example: some implementations of traits.
5170 *
5171 * 4) Starting with C++20, when the compiler sees `a == b`, it also uses
5172 * `b == a` when constructing the overload set. For us this means that
5173 * when the compiler handles `ExprLhs<T> == b`, it also tries to resolve
5174 * the overload set for `b == ExprLhs<T>`.
5175 *
5176 * To accomodate these use cases, decomposer ended up rather complex.
5177 *
5178 * 1) These types are handled by adding SFINAE overloads to our comparison
5179 * operators, checking whether `T == U` are comparable with the given
5180 * operator, and if not, whether T (or U) are comparable with literal 0.
5181 * If yes, the overload compares T (or U) with 0 literal inline in the
5182 * definition.
5183 *
5184 * Note that for extra correctness, we check that the other type is
5185 * either an `int` (literal 0 is captured as `int` by templates), or
5186 * a `long` (some platforms use 0L for `NULL` and we want to support
5187 * that for pointer comparisons).
5188 *
5189 * 2) For these types, `is_foo_comparable<T, int>` is true, but letting
5190 * them fall into the overload that actually does `T == int` causes
5191 * compilation error. Handling them requires that the decomposition
5192 * is `constexpr`, so that P2564R3 applies and the `consteval` from
5193 * their accompanying magic type is propagated through the `constexpr`
5194 * call stack.
5195 *
5196 * However this is not enough to handle these types automatically,
5197 * because our default is to capture types by reference, to avoid
5198 * runtime copies. While these references cannot become dangling,
5199 * they outlive the constexpr context and thus the default capture
5200 * path cannot be actually constexpr.
5201 *
5202 * The solution is to capture these types by value, by explicitly
5203 * specializing `Catch::capture_by_value` for them. Catch2 provides
5204 * specialization for `std::foo_ordering`s, but users can specialize
5205 * the trait for their own types as well.
5206 *
5207 * 3) If a type has no linkage, we also cannot capture it by reference.
5208 * The solution is once again to capture them by value. We handle
5209 * the common cases by using `std::is_arithmetic` as the default
5210 * for `Catch::capture_by_value`, but that is only a some-effort
5211 * heuristic. But as with 2), users can specialize `capture_by_value`
5212 * for their own types as needed.
5213 *
5214 * 4) To support C++20 and make the SFINAE on our decomposing operators
5215 * work, the SFINAE has to happen in return type, rather than in
5216 * a template type. This is due to our use of logical type traits
5217 * (`conjunction`/`disjunction`/`negation`), that we use to workaround
5218 * an issue in older (9-) versions of GCC. I still blame C++20 for
5219 * this, because without the comparison order switching, the logical
5220 * traits could still be used in template type.
5221 *
5222 * There are also other side concerns, e.g. supporting both `REQUIRE(a)`
5223 * and `REQUIRE(a == b)`, or making `REQUIRE_THAT(a, IsEqual(b))` slot
5224 * nicely into the same expression handling logic, but these are rather
5225 * straightforward and add only a bit of complexity (e.g. common base
5226 * class for decomposed expressions).
5227 */
5228
5229#ifdef _MSC_VER
5230#pragma warning(push)
5231#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
5232#pragma warning(disable:4018) // more "signed/unsigned mismatch"
5233#pragma warning(disable:4312) // Converting int to T* using reinterpret_cast (issue on x64 platform)
5234#pragma warning(disable:4180) // qualifier applied to function type has no meaning
5235#pragma warning(disable:4800) // Forcing result to true or false
5236#endif
5237
5238#ifdef __clang__
5239# pragma clang diagnostic push
5240# pragma clang diagnostic ignored "-Wsign-compare"
5241# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
5242#elif defined __GNUC__
5243# pragma GCC diagnostic push
5244# pragma GCC diagnostic ignored "-Wsign-compare"
5245# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
5246#endif
5247
5248#if defined(CATCH_CPP20_OR_GREATER) && __has_include(<compare>)
5249# include <compare>
5250# if defined( __cpp_lib_three_way_comparison ) && \
5251 __cpp_lib_three_way_comparison >= 201907L
5252# define CATCH_CONFIG_CPP20_COMPARE_OVERLOADS
5253# endif
5254#endif
5255
5256namespace Catch {
5257
5258 namespace Detail {
5259 // This was added in C++20, but we require only C++14 for now.
5260 template <typename T>
5261 using RemoveCVRef_t = std::remove_cv_t<std::remove_reference_t<T>>;
5262 }
5263
5264 // Note: There is nothing that stops us from extending this,
5265 // e.g. to `std::is_scalar`, but the more encompassing
5266 // traits are usually also more expensive. For now we
5267 // keep this as it used to be and it can be changed later.
5268 template <typename T>
5269 struct capture_by_value
5270 : std::integral_constant<bool, std::is_arithmetic<T>{}> {};
5271
5272#if defined( CATCH_CONFIG_CPP20_COMPARE_OVERLOADS )
5273 template <>
5274 struct capture_by_value<std::strong_ordering> : std::true_type {};
5275 template <>
5276 struct capture_by_value<std::weak_ordering> : std::true_type {};
5277 template <>
5278 struct capture_by_value<std::partial_ordering> : std::true_type {};
5279#endif
5280
5281 template <typename T>
5282 struct always_false : std::false_type {};
5283
5284 class ITransientExpression {
5285 bool m_isBinaryExpression;
5286 bool m_result;
5287
5288 protected:
5289 ~ITransientExpression() = default;
5290
5291 public:
5292 constexpr auto isBinaryExpression() const -> bool { return m_isBinaryExpression; }
5293 constexpr auto getResult() const -> bool { return m_result; }
5294 //! This function **has** to be overriden by the derived class.
5295 virtual void streamReconstructedExpression( std::ostream& os ) const;
5296
5297 constexpr ITransientExpression( bool isBinaryExpression, bool result )
5298 : m_isBinaryExpression( isBinaryExpression ),
5299 m_result( result )
5300 {}
5301
5302 constexpr ITransientExpression( ITransientExpression const& ) = default;
5303 constexpr ITransientExpression& operator=( ITransientExpression const& ) = default;
5304
5305 friend std::ostream& operator<<(std::ostream& out, ITransientExpression const& expr) {
5306 expr.streamReconstructedExpression(out);
5307 return out;
5308 }
5309 };
5310
5311 void formatReconstructedExpression( std::ostream &os, std::string const& lhs, StringRef op, std::string const& rhs );
5312
5313 template<typename LhsT, typename RhsT>
5314 class BinaryExpr : public ITransientExpression {
5315 LhsT m_lhs;
5316 StringRef m_op;
5317 RhsT m_rhs;
5318
5319 void streamReconstructedExpression( std::ostream &os ) const override {
5320 formatReconstructedExpression
5321 ( os, Catch::Detail::stringify( m_lhs ), m_op, Catch::Detail::stringify( m_rhs ) );
5322 }
5323
5324 public:
5325 constexpr BinaryExpr( bool comparisonResult, LhsT lhs, StringRef op, RhsT rhs )
5326 : ITransientExpression{ true, comparisonResult },
5327 m_lhs( lhs ),
5328 m_op( op ),
5329 m_rhs( rhs )
5330 {}
5331
5332 template<typename T>
5333 auto operator && ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5334 static_assert(always_false<T>::value,
5335 "chained comparisons are not supported inside assertions, "
5336 "wrap the expression inside parentheses, or decompose it");
5337 }
5338
5339 template<typename T>
5340 auto operator || ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5341 static_assert(always_false<T>::value,
5342 "chained comparisons are not supported inside assertions, "
5343 "wrap the expression inside parentheses, or decompose it");
5344 }
5345
5346 template<typename T>
5347 auto operator == ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5348 static_assert(always_false<T>::value,
5349 "chained comparisons are not supported inside assertions, "
5350 "wrap the expression inside parentheses, or decompose it");
5351 }
5352
5353 template<typename T>
5354 auto operator != ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5355 static_assert(always_false<T>::value,
5356 "chained comparisons are not supported inside assertions, "
5357 "wrap the expression inside parentheses, or decompose it");
5358 }
5359
5360 template<typename T>
5361 auto operator > ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5362 static_assert(always_false<T>::value,
5363 "chained comparisons are not supported inside assertions, "
5364 "wrap the expression inside parentheses, or decompose it");
5365 }
5366
5367 template<typename T>
5368 auto operator < ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5369 static_assert(always_false<T>::value,
5370 "chained comparisons are not supported inside assertions, "
5371 "wrap the expression inside parentheses, or decompose it");
5372 }
5373
5374 template<typename T>
5375 auto operator >= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5376 static_assert(always_false<T>::value,
5377 "chained comparisons are not supported inside assertions, "
5378 "wrap the expression inside parentheses, or decompose it");
5379 }
5380
5381 template<typename T>
5382 auto operator <= ( T ) const -> BinaryExpr<LhsT, RhsT const&> const {
5383 static_assert(always_false<T>::value,
5384 "chained comparisons are not supported inside assertions, "
5385 "wrap the expression inside parentheses, or decompose it");
5386 }
5387 };
5388
5389 template<typename LhsT>
5390 class UnaryExpr : public ITransientExpression {
5391 LhsT m_lhs;
5392
5393 void streamReconstructedExpression( std::ostream &os ) const override {
5394 os << Catch::Detail::stringify( m_lhs );
5395 }
5396
5397 public:
5398 explicit constexpr UnaryExpr( LhsT lhs )
5399 : ITransientExpression{ false, static_cast<bool>(lhs) },
5400 m_lhs( lhs )
5401 {}
5402 };
5403
5404
5405 template<typename LhsT>
5406 class ExprLhs {
5407 LhsT m_lhs;
5408 public:
5409 explicit constexpr ExprLhs( LhsT lhs ) : m_lhs( lhs ) {}
5410
5411#define CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( id, op ) \
5412 template <typename RhsT> \
5413 constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
5414 -> std::enable_if_t< \
5415 Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
5416 Detail::negation<capture_by_value< \
5417 Detail::RemoveCVRef_t<RhsT>>>>::value, \
5418 BinaryExpr<LhsT, RhsT const&>> { \
5419 return { \
5420 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5421 } \
5422 template <typename RhsT> \
5423 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5424 -> std::enable_if_t< \
5425 Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
5426 capture_by_value<RhsT>>::value, \
5427 BinaryExpr<LhsT, RhsT>> { \
5428 return { \
5429 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5430 } \
5431 template <typename RhsT> \
5432 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5433 -> std::enable_if_t< \
5434 Detail::conjunction< \
5435 Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
5436 Detail::is_eq_0_comparable<LhsT>, \
5437 /* We allow long because we want `ptr op NULL` to be accepted */ \
5438 Detail::disjunction<std::is_same<RhsT, int>, \
5439 std::is_same<RhsT, long>>>::value, \
5440 BinaryExpr<LhsT, RhsT>> { \
5441 if ( rhs != 0 ) { throw_test_failure_exception(); } \
5442 return { \
5443 static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
5444 } \
5445 template <typename RhsT> \
5446 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5447 -> std::enable_if_t< \
5448 Detail::conjunction< \
5449 Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
5450 Detail::is_eq_0_comparable<RhsT>, \
5451 /* We allow long because we want `ptr op NULL` to be accepted */ \
5452 Detail::disjunction<std::is_same<LhsT, int>, \
5453 std::is_same<LhsT, long>>>::value, \
5454 BinaryExpr<LhsT, RhsT>> { \
5455 if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
5456 return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5457 }
5458
5459 CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( eq, == )
5460 CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR( ne, != )
5461
5462 #undef CATCH_INTERNAL_DEFINE_EXPRESSION_EQUALITY_OPERATOR
5463
5464
5465#define CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( id, op ) \
5466 template <typename RhsT> \
5467 constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
5468 -> std::enable_if_t< \
5469 Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
5470 Detail::negation<capture_by_value< \
5471 Detail::RemoveCVRef_t<RhsT>>>>::value, \
5472 BinaryExpr<LhsT, RhsT const&>> { \
5473 return { \
5474 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5475 } \
5476 template <typename RhsT> \
5477 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5478 -> std::enable_if_t< \
5479 Detail::conjunction<Detail::is_##id##_comparable<LhsT, RhsT>, \
5480 capture_by_value<RhsT>>::value, \
5481 BinaryExpr<LhsT, RhsT>> { \
5482 return { \
5483 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5484 } \
5485 template <typename RhsT> \
5486 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5487 -> std::enable_if_t< \
5488 Detail::conjunction< \
5489 Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
5490 Detail::is_##id##_0_comparable<LhsT>, \
5491 std::is_same<RhsT, int>>::value, \
5492 BinaryExpr<LhsT, RhsT>> { \
5493 if ( rhs != 0 ) { throw_test_failure_exception(); } \
5494 return { \
5495 static_cast<bool>( lhs.m_lhs op 0 ), lhs.m_lhs, #op##_sr, rhs }; \
5496 } \
5497 template <typename RhsT> \
5498 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5499 -> std::enable_if_t< \
5500 Detail::conjunction< \
5501 Detail::negation<Detail::is_##id##_comparable<LhsT, RhsT>>, \
5502 Detail::is_##id##_0_comparable<RhsT>, \
5503 std::is_same<LhsT, int>>::value, \
5504 BinaryExpr<LhsT, RhsT>> { \
5505 if ( lhs.m_lhs != 0 ) { throw_test_failure_exception(); } \
5506 return { static_cast<bool>( 0 op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5507 }
5508
5509 CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( lt, < )
5510 CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( le, <= )
5511 CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( gt, > )
5512 CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR( ge, >= )
5513
5514 #undef CATCH_INTERNAL_DEFINE_EXPRESSION_COMPARISON_OPERATOR
5515
5516
5517#define CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR( op ) \
5518 template <typename RhsT> \
5519 constexpr friend auto operator op( ExprLhs&& lhs, RhsT&& rhs ) \
5520 -> std::enable_if_t< \
5521 !capture_by_value<Detail::RemoveCVRef_t<RhsT>>::value, \
5522 BinaryExpr<LhsT, RhsT const&>> { \
5523 return { \
5524 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5525 } \
5526 template <typename RhsT> \
5527 constexpr friend auto operator op( ExprLhs&& lhs, RhsT rhs ) \
5528 -> std::enable_if_t<capture_by_value<RhsT>::value, \
5529 BinaryExpr<LhsT, RhsT>> { \
5530 return { \
5531 static_cast<bool>( lhs.m_lhs op rhs ), lhs.m_lhs, #op##_sr, rhs }; \
5532 }
5533
5534 CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(|)
5535 CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(&)
5536 CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR(^)
5537
5538 #undef CATCH_INTERNAL_DEFINE_EXPRESSION_OPERATOR
5539
5540 template<typename RhsT>
5541 friend auto operator && ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
5542 static_assert(always_false<RhsT>::value,
5543 "operator&& is not supported inside assertions, "
5544 "wrap the expression inside parentheses, or decompose it");
5545 }
5546
5547 template<typename RhsT>
5548 friend auto operator || ( ExprLhs &&, RhsT && ) -> BinaryExpr<LhsT, RhsT const&> {
5549 static_assert(always_false<RhsT>::value,
5550 "operator|| is not supported inside assertions, "
5551 "wrap the expression inside parentheses, or decompose it");
5552 }
5553
5554 constexpr auto makeUnaryExpr() const -> UnaryExpr<LhsT> {
5555 return UnaryExpr<LhsT>{ m_lhs };
5556 }
5557 };
5558
5559 struct Decomposer {
5560 template <typename T,
5561 std::enable_if_t<!capture_by_value<Detail::RemoveCVRef_t<T>>::value,
5562 int> = 0>
5563 constexpr friend auto operator <= ( Decomposer &&, T && lhs ) -> ExprLhs<T const&> {
5564 return ExprLhs<const T&>{ lhs };
5565 }
5566
5567 template <typename T,
5568 std::enable_if_t<capture_by_value<T>::value, int> = 0>
5569 constexpr friend auto operator <= ( Decomposer &&, T value ) -> ExprLhs<T> {
5570 return ExprLhs<T>{ value };
5571 }
5572 };
5573
5574} // end namespace Catch
5575
5576#ifdef _MSC_VER
5577#pragma warning(pop)
5578#endif
5579#ifdef __clang__
5580# pragma clang diagnostic pop
5581#elif defined __GNUC__
5582# pragma GCC diagnostic pop
5583#endif
5584
5585#endif // CATCH_DECOMPOSER_HPP_INCLUDED
5586
5587#include <string>
5588
5589namespace Catch {
5590
5591 struct AssertionReaction {
5592 bool shouldDebugBreak = false;
5593 bool shouldThrow = false;
5594 bool shouldSkip = false;
5595 };
5596
5597 class AssertionHandler {
5598 AssertionInfo m_assertionInfo;
5599 AssertionReaction m_reaction;
5600 bool m_completed = false;
5601 IResultCapture& m_resultCapture;
5602
5603 public:
5604 AssertionHandler
5605 ( StringRef macroName,
5606 SourceLineInfo const& lineInfo,
5607 StringRef capturedExpression,
5608 ResultDisposition::Flags resultDisposition );
5609 ~AssertionHandler() {
5610 if ( !m_completed ) {
5611 m_resultCapture.handleIncomplete( m_assertionInfo );
5612 }
5613 }
5614
5615
5616 template<typename T>
5617 constexpr void handleExpr( ExprLhs<T> const& expr ) {
5618 handleExpr( expr.makeUnaryExpr() );
5619 }
5620 void handleExpr( ITransientExpression const& expr );
5621
5622 void handleMessage(ResultWas::OfType resultType, std::string&& message);
5623
5624 void handleExceptionThrownAsExpected();
5625 void handleUnexpectedExceptionNotThrown();
5626 void handleExceptionNotThrownAsExpected();
5627 void handleThrowingCallSkipped();
5628 void handleUnexpectedInflightException();
5629
5630 void complete();
5631
5632 // query
5633 auto allowThrows() const -> bool;
5634 };
5635
5636 void handleExceptionMatchExpr( AssertionHandler& handler, std::string const& str );
5637
5638} // namespace Catch
5639
5640#endif // CATCH_ASSERTION_HANDLER_HPP_INCLUDED
5641
5642
5643#ifndef CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
5644#define CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
5645
5646
5647#if !defined(CATCH_CONFIG_DISABLE_STRINGIFICATION)
5648 #define CATCH_INTERNAL_STRINGIFY(...) #__VA_ARGS__##_catch_sr
5649#else
5650 #define CATCH_INTERNAL_STRINGIFY(...) "Disabled by CATCH_CONFIG_DISABLE_STRINGIFICATION"_catch_sr
5651#endif
5652
5653#endif // CATCH_PREPROCESSOR_INTERNAL_STRINGIFY_HPP_INCLUDED
5654
5655// We need this suppression to leak, because it took until GCC 10
5656// for the front end to handle local suppression via _Pragma properly
5657#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && __GNUC__ <= 9
5658 #pragma GCC diagnostic ignored "-Wparentheses"
5659#endif
5660
5661#if !defined(CATCH_CONFIG_DISABLE)
5662
5663#if defined(CATCH_CONFIG_FAST_COMPILE) || defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
5664
5665///////////////////////////////////////////////////////////////////////////////
5666// Another way to speed-up compilation is to omit local try-catch for REQUIRE*
5667// macros.
5668#define INTERNAL_CATCH_TRY
5669#define INTERNAL_CATCH_CATCH( capturer )
5670
5671#else // CATCH_CONFIG_FAST_COMPILE
5672
5673#define INTERNAL_CATCH_TRY try
5674#define INTERNAL_CATCH_CATCH( handler ) catch(...) { (handler).handleUnexpectedInflightException(); }
5675
5676#endif
5677
5678///////////////////////////////////////////////////////////////////////////////
5679#define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \
5680 do { /* NOLINT(bugprone-infinite-loop) */ \
5681 /* The expression should not be evaluated, but warnings should hopefully be checked */ \
5682 CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \
5683 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
5684 INTERNAL_CATCH_TRY { \
5685 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5686 CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
5687 catchAssertionHandler.handleExpr( Catch::Decomposer() <= __VA_ARGS__ ); /* NOLINT(bugprone-chained-comparison) */ \
5688 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
5689 } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
5690 catchAssertionHandler.complete(); \
5691 } while( (void)0, (false) && static_cast<const bool&>( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look
5692 // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.
5693
5694///////////////////////////////////////////////////////////////////////////////
5695#define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \
5696 INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
5697 if( Catch::getResultCapture().lastAssertionPassed() )
5698
5699///////////////////////////////////////////////////////////////////////////////
5700#define INTERNAL_CATCH_ELSE( macroName, resultDisposition, ... ) \
5701 INTERNAL_CATCH_TEST( macroName, resultDisposition, __VA_ARGS__ ); \
5702 if( !Catch::getResultCapture().lastAssertionPassed() )
5703
5704///////////////////////////////////////////////////////////////////////////////
5705#define INTERNAL_CATCH_NO_THROW( macroName, resultDisposition, ... ) \
5706 do { \
5707 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \
5708 try { \
5709 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5710 CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
5711 static_cast<void>(__VA_ARGS__); \
5712 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
5713 catchAssertionHandler.handleExceptionNotThrownAsExpected(); \
5714 } \
5715 catch( ... ) { \
5716 catchAssertionHandler.handleUnexpectedInflightException(); \
5717 } \
5718 catchAssertionHandler.complete(); \
5719 } while( false )
5720
5721///////////////////////////////////////////////////////////////////////////////
5722#define INTERNAL_CATCH_THROWS( macroName, resultDisposition, ... ) \
5723 do { \
5724 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition); \
5725 if( catchAssertionHandler.allowThrows() ) \
5726 try { \
5727 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5728 CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
5729 CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
5730 static_cast<void>(__VA_ARGS__); \
5731 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
5732 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
5733 } \
5734 catch( ... ) { \
5735 catchAssertionHandler.handleExceptionThrownAsExpected(); \
5736 } \
5737 else \
5738 catchAssertionHandler.handleThrowingCallSkipped(); \
5739 catchAssertionHandler.complete(); \
5740 } while( false )
5741
5742///////////////////////////////////////////////////////////////////////////////
5743#define INTERNAL_CATCH_THROWS_AS( macroName, exceptionType, resultDisposition, expr ) \
5744 do { \
5745 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(expr) ", " CATCH_INTERNAL_STRINGIFY(exceptionType), resultDisposition ); \
5746 if( catchAssertionHandler.allowThrows() ) \
5747 try { \
5748 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5749 CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
5750 CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
5751 static_cast<void>(expr); \
5752 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
5753 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
5754 } \
5755 catch( exceptionType const& ) { \
5756 catchAssertionHandler.handleExceptionThrownAsExpected(); \
5757 } \
5758 catch( ... ) { \
5759 catchAssertionHandler.handleUnexpectedInflightException(); \
5760 } \
5761 else \
5762 catchAssertionHandler.handleThrowingCallSkipped(); \
5763 catchAssertionHandler.complete(); \
5764 } while( false )
5765
5766
5767
5768///////////////////////////////////////////////////////////////////////////////
5769// Although this is matcher-based, it can be used with just a string
5770#define INTERNAL_CATCH_THROWS_STR_MATCHES( macroName, resultDisposition, matcher, ... ) \
5771 do { \
5772 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
5773 if( catchAssertionHandler.allowThrows() ) \
5774 try { \
5775 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5776 CATCH_INTERNAL_SUPPRESS_UNUSED_RESULT \
5777 CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
5778 static_cast<void>(__VA_ARGS__); \
5779 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
5780 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
5781 } \
5782 catch( ... ) { \
5783 Catch::handleExceptionMatchExpr( catchAssertionHandler, matcher ); \
5784 } \
5785 else \
5786 catchAssertionHandler.handleThrowingCallSkipped(); \
5787 catchAssertionHandler.complete(); \
5788 } while( false )
5789
5790#endif // CATCH_CONFIG_DISABLE
5791
5792#endif // CATCH_TEST_MACRO_IMPL_HPP_INCLUDED
5793
5794
5795#ifndef CATCH_SECTION_HPP_INCLUDED
5796#define CATCH_SECTION_HPP_INCLUDED
5797
5798
5799
5800
5801/** \file
5802 * Wrapper for the STATIC_ANALYSIS_SUPPORT configuration option
5803 *
5804 * Some of Catch2's macros can be defined differently to work better with
5805 * static analysis tools, like clang-tidy or coverity.
5806 * Currently the main use case is to show that `SECTION`s are executed
5807 * exclusively, and not all in one run of a `TEST_CASE`.
5808 */
5809
5810#ifndef CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
5811#define CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
5812
5813
5814#if defined(__clang_analyzer__) || defined(__COVERITY__)
5815 #define CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT
5816#endif
5817
5818#if defined( CATCH_INTERNAL_CONFIG_STATIC_ANALYSIS_SUPPORT ) && \
5819 !defined( CATCH_CONFIG_NO_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT ) && \
5820 !defined( CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT )
5821# define CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
5822#endif
5823
5824
5825#endif // CATCH_CONFIG_STATIC_ANALYSIS_SUPPORT_HPP_INCLUDED
5826
5827
5828#ifndef CATCH_TIMER_HPP_INCLUDED
5829#define CATCH_TIMER_HPP_INCLUDED
5830
5831#include <cstdint>
5832
5833namespace Catch {
5834
5835 class Timer {
5836 uint64_t m_nanoseconds = 0;
5837 public:
5838 void start();
5839 auto getElapsedNanoseconds() const -> uint64_t;
5840 auto getElapsedMicroseconds() const -> uint64_t;
5841 auto getElapsedMilliseconds() const -> unsigned int;
5842 auto getElapsedSeconds() const -> double;
5843 };
5844
5845} // namespace Catch
5846
5847#endif // CATCH_TIMER_HPP_INCLUDED
5848
5849namespace Catch {
5850
5851 class Section : Detail::NonCopyable {
5852 public:
5853 Section( SectionInfo&& info );
5854 Section( SourceLineInfo const& _lineInfo,
5855 StringRef _name,
5856 const char* const = nullptr );
5857 ~Section();
5858
5859 // This indicates whether the section should be executed or not
5860 explicit operator bool() const;
5861
5862 private:
5863 SectionInfo m_info;
5864
5865 Counts m_assertions;
5866 bool m_sectionIncluded;
5867 Timer m_timer;
5868 };
5869
5870} // end namespace Catch
5871
5872#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
5873# define INTERNAL_CATCH_SECTION( ... ) \
5874 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5875 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
5876 if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
5877 catch_internal_Section ) = \
5878 Catch::Section( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) ) \
5879 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5880
5881# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
5882 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5883 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
5884 if ( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( \
5885 catch_internal_Section ) = \
5886 Catch::SectionInfo( \
5887 CATCH_INTERNAL_LINEINFO, \
5888 ( Catch::ReusableStringStream() << __VA_ARGS__ ) \
5889 .str() ) ) \
5890 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5891
5892#else
5893
5894// These section definitions imply that at most one section at one level
5895// will be intered (because only one section's __LINE__ can be equal to
5896// the dummy `catchInternalSectionHint` variable from `TEST_CASE`).
5897
5898namespace Catch {
5899 namespace Detail {
5900 // Intentionally without linkage, as it should only be used as a dummy
5901 // symbol for static analysis.
5902 // The arguments are used as a dummy for checking warnings in the passed
5903 // expressions.
5904 int GetNewSectionHint( StringRef, const char* const = nullptr );
5905 } // namespace Detail
5906} // namespace Catch
5907
5908
5909# define INTERNAL_CATCH_SECTION( ... ) \
5910 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5911 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
5912 CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
5913 if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
5914 catchInternalSectionHint, \
5915 catchInternalSectionHint = \
5916 Catch::Detail::GetNewSectionHint(__VA_ARGS__); \
5917 catchInternalPreviousSectionHint == __LINE__ ) \
5918 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5919
5920# define INTERNAL_CATCH_DYNAMIC_SECTION( ... ) \
5921 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
5922 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
5923 CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
5924 if ( [[maybe_unused]] const int catchInternalPreviousSectionHint = \
5925 catchInternalSectionHint, \
5926 catchInternalSectionHint = Catch::Detail::GetNewSectionHint( \
5927 ( Catch::ReusableStringStream() << __VA_ARGS__ ).str()); \
5928 catchInternalPreviousSectionHint == __LINE__ ) \
5929 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
5930
5931#endif
5932
5933
5934#endif // CATCH_SECTION_HPP_INCLUDED
5935
5936
5937#ifndef CATCH_TEST_REGISTRY_HPP_INCLUDED
5938#define CATCH_TEST_REGISTRY_HPP_INCLUDED
5939
5940
5941
5942#ifndef CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
5943#define CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
5944
5945namespace Catch {
5946
5947 class ITestInvoker {
5948 public:
5949 virtual void prepareTestCase();
5950 virtual void tearDownTestCase();
5951 virtual void invoke() const = 0;
5952 virtual ~ITestInvoker(); // = default
5953 };
5954
5955} // namespace Catch
5956
5957#endif // CATCH_INTERFACES_TEST_INVOKER_HPP_INCLUDED
5958
5959
5960#ifndef CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
5961#define CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
5962
5963#define INTERNAL_CATCH_EXPAND1( param ) INTERNAL_CATCH_EXPAND2( param )
5964#define INTERNAL_CATCH_EXPAND2( ... ) INTERNAL_CATCH_NO##__VA_ARGS__
5965#define INTERNAL_CATCH_DEF( ... ) INTERNAL_CATCH_DEF __VA_ARGS__
5966#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
5967
5968#define INTERNAL_CATCH_REMOVE_PARENS( ... ) \
5969 INTERNAL_CATCH_EXPAND1( INTERNAL_CATCH_DEF __VA_ARGS__ )
5970
5971#endif // CATCH_PREPROCESSOR_REMOVE_PARENS_HPP_INCLUDED
5972
5973// GCC 5 and older do not properly handle disabling unused-variable warning
5974// with a _Pragma. This means that we have to leak the suppression to the
5975// user code as well :-(
5976#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
5977#pragma GCC diagnostic ignored "-Wunused-variable"
5978#endif
5979
5980
5981
5982namespace Catch {
5983
5984template<typename C>
5985class TestInvokerAsMethod : public ITestInvoker {
5986 void (C::*m_testAsMethod)();
5987public:
5988 constexpr TestInvokerAsMethod( void ( C::*testAsMethod )() ) noexcept:
5989 m_testAsMethod( testAsMethod ) {}
5990
5991 void invoke() const override {
5992 C obj;
5993 (obj.*m_testAsMethod)();
5994 }
5995};
5996
5997Detail::unique_ptr<ITestInvoker> makeTestInvoker( void(*testAsFunction)() );
5998
5999template<typename C>
6000Detail::unique_ptr<ITestInvoker> makeTestInvoker( void (C::*testAsMethod)() ) {
6001 return Detail::make_unique<TestInvokerAsMethod<C>>( testAsMethod );
6002}
6003
6004template <typename C>
6005class TestInvokerFixture : public ITestInvoker {
6006 void ( C::*m_testAsMethod )() const;
6007 Detail::unique_ptr<C> m_fixture = nullptr;
6008
6009public:
6010 constexpr TestInvokerFixture( void ( C::*testAsMethod )() const ) noexcept:
6011 m_testAsMethod( testAsMethod ) {}
6012
6013 void prepareTestCase() override {
6014 m_fixture = Detail::make_unique<C>();
6015 }
6016
6017 void tearDownTestCase() override {
6018 m_fixture.reset();
6019 }
6020
6021 void invoke() const override {
6022 auto* f = m_fixture.get();
6023 ( f->*m_testAsMethod )();
6024 }
6025};
6026
6027template<typename C>
6028Detail::unique_ptr<ITestInvoker> makeTestInvokerFixture( void ( C::*testAsMethod )() const ) {
6029 return Detail::make_unique<TestInvokerFixture<C>>( testAsMethod );
6030}
6031
6032struct NameAndTags {
6033 constexpr NameAndTags( StringRef name_ = StringRef(),
6034 StringRef tags_ = StringRef() ) noexcept:
6035 name( name_ ), tags( tags_ ) {}
6036 StringRef name;
6037 StringRef tags;
6038};
6039
6040struct AutoReg : Detail::NonCopyable {
6041 AutoReg( Detail::unique_ptr<ITestInvoker> invoker, SourceLineInfo const& lineInfo, StringRef classOrMethod, NameAndTags const& nameAndTags ) noexcept;
6042};
6043
6044} // end namespace Catch
6045
6046#if defined(CATCH_CONFIG_DISABLE)
6047 #define INTERNAL_CATCH_TESTCASE_NO_REGISTRATION( TestName, ... ) \
6048 static inline void TestName()
6049 #define INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION( TestName, ClassName, ... ) \
6050 namespace{ \
6051 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
6052 void test(); \
6053 }; \
6054 } \
6055 void TestName::test()
6056#endif
6057
6058
6059#if !defined(CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT)
6060
6061 ///////////////////////////////////////////////////////////////////////////////
6062 #define INTERNAL_CATCH_TESTCASE2( TestName, ... ) \
6063 static void TestName(); \
6064 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6065 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6066 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6067 namespace{ const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( &TestName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); } /* NOLINT */ \
6068 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6069 static void TestName()
6070 #define INTERNAL_CATCH_TESTCASE( ... ) \
6071 INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__ )
6072
6073#else // ^^ !CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT | vv CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
6074
6075
6076// Dummy registrator for the dumy test case macros
6077namespace Catch {
6078 namespace Detail {
6079 struct DummyUse {
6080 DummyUse( void ( * )( int ), Catch::NameAndTags const& );
6081 };
6082 } // namespace Detail
6083} // namespace Catch
6084
6085// Note that both the presence of the argument and its exact name are
6086// necessary for the section support.
6087
6088// We provide a shadowed variable so that a `SECTION` inside non-`TEST_CASE`
6089// tests can compile. The redefined `TEST_CASE` shadows this with param.
6090static int catchInternalSectionHint = 0;
6091
6092# define INTERNAL_CATCH_TESTCASE2( fname, ... ) \
6093 static void fname( int ); \
6094 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6095 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6096 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6097 static const Catch::Detail::DummyUse INTERNAL_CATCH_UNIQUE_NAME( \
6098 dummyUser )( &(fname), Catch::NameAndTags{ __VA_ARGS__ } ); \
6099 CATCH_INTERNAL_SUPPRESS_SHADOW_WARNINGS \
6100 static void fname( [[maybe_unused]] int catchInternalSectionHint ) \
6101 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
6102# define INTERNAL_CATCH_TESTCASE( ... ) \
6103 INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( dummyFunction ), __VA_ARGS__ )
6104
6105
6106#endif // CATCH_CONFIG_EXPERIMENTAL_STATIC_ANALYSIS_SUPPORT
6107
6108 ///////////////////////////////////////////////////////////////////////////////
6109 #define INTERNAL_CATCH_TEST_CASE_METHOD2( TestName, ClassName, ... )\
6110 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6111 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6112 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6113 namespace{ \
6114 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName) { \
6115 void test(); \
6116 }; \
6117 const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
6118 Catch::makeTestInvoker( &TestName::test ), \
6119 CATCH_INTERNAL_LINEINFO, \
6120 #ClassName##_catch_sr, \
6121 Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
6122 } \
6123 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6124 void TestName::test()
6125 #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \
6126 INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
6127
6128 ///////////////////////////////////////////////////////////////////////////////
6129 #define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( TestName, ClassName, ... ) \
6130 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6131 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6132 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6133 namespace { \
6134 struct TestName : INTERNAL_CATCH_REMOVE_PARENS( ClassName ) { \
6135 void test() const; \
6136 }; \
6137 const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
6138 Catch::makeTestInvokerFixture( &TestName::test ), \
6139 CATCH_INTERNAL_LINEINFO, \
6140 #ClassName##_catch_sr, \
6141 Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
6142 } \
6143 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6144 void TestName::test() const
6145 #define INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( ClassName, ... ) \
6146 INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), ClassName, __VA_ARGS__ )
6147
6148
6149 ///////////////////////////////////////////////////////////////////////////////
6150 #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
6151 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6152 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6153 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6154 namespace { \
6155 const Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( \
6156 Catch::makeTestInvoker( &QualifiedMethod ), \
6157 CATCH_INTERNAL_LINEINFO, \
6158 "&" #QualifiedMethod##_catch_sr, \
6159 Catch::NameAndTags{ __VA_ARGS__ } ); \
6160 } /* NOLINT */ \
6161 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
6162
6163
6164 ///////////////////////////////////////////////////////////////////////////////
6165 #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \
6166 do { \
6167 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6168 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6169 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6170 Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( Catch::makeTestInvoker( Function ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ __VA_ARGS__ } ); /* NOLINT */ \
6171 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6172 } while(false)
6173
6174
6175#endif // CATCH_TEST_REGISTRY_HPP_INCLUDED
6176
6177
6178// All of our user-facing macros support configuration toggle, that
6179// forces them to be defined prefixed with CATCH_. We also like to
6180// support another toggle that can minimize (disable) their implementation.
6181// Given this, we have 4 different configuration options below
6182
6183#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
6184
6185 #define CATCH_REQUIRE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6186 #define CATCH_REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
6187
6188 #define CATCH_REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6189 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
6190 #define CATCH_REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6191
6192 #define CATCH_CHECK( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6193 #define CATCH_CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
6194 #define CATCH_CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CATCH_CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6195 #define CATCH_CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CATCH_CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6196 #define CATCH_CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CATCH_CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6197
6198 #define CATCH_CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CATCH_CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6199 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CATCH_CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
6200 #define CATCH_CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CATCH_CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6201
6202 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
6203 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
6204 #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
6205 #define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
6206 #define CATCH_REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
6207 #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
6208 #define CATCH_DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
6209 #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
6210 #define CATCH_FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "CATCH_FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6211 #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( "CATCH_SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6212 #define CATCH_SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
6213
6214
6215 #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
6216 #define CATCH_STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
6217 #define CATCH_STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
6218 #define CATCH_STATIC_CHECK( ... ) static_assert( __VA_ARGS__ , #__VA_ARGS__ ); CATCH_SUCCEED( #__VA_ARGS__ )
6219 #define CATCH_STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); CATCH_SUCCEED( #__VA_ARGS__ )
6220 #else
6221 #define CATCH_STATIC_REQUIRE( ... ) CATCH_REQUIRE( __VA_ARGS__ )
6222 #define CATCH_STATIC_REQUIRE_FALSE( ... ) CATCH_REQUIRE_FALSE( __VA_ARGS__ )
6223 #define CATCH_STATIC_CHECK( ... ) CATCH_CHECK( __VA_ARGS__ )
6224 #define CATCH_STATIC_CHECK_FALSE( ... ) CATCH_CHECK_FALSE( __VA_ARGS__ )
6225 #endif
6226
6227
6228 // "BDD-style" convenience wrappers
6229 #define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
6230 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
6231 #define CATCH_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
6232 #define CATCH_AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
6233 #define CATCH_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
6234 #define CATCH_AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
6235 #define CATCH_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
6236 #define CATCH_AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
6237
6238#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, implemented | vv prefixed, disabled
6239
6240 #define CATCH_REQUIRE( ... ) (void)(0)
6241 #define CATCH_REQUIRE_FALSE( ... ) (void)(0)
6242
6243 #define CATCH_REQUIRE_THROWS( ... ) (void)(0)
6244 #define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
6245 #define CATCH_REQUIRE_NOTHROW( ... ) (void)(0)
6246
6247 #define CATCH_CHECK( ... ) (void)(0)
6248 #define CATCH_CHECK_FALSE( ... ) (void)(0)
6249 #define CATCH_CHECKED_IF( ... ) if (__VA_ARGS__)
6250 #define CATCH_CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
6251 #define CATCH_CHECK_NOFAIL( ... ) (void)(0)
6252
6253 #define CATCH_CHECK_THROWS( ... ) (void)(0)
6254 #define CATCH_CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
6255 #define CATCH_CHECK_NOTHROW( ... ) (void)(0)
6256
6257 #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
6258 #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
6259 #define CATCH_METHOD_AS_TEST_CASE( method, ... )
6260 #define CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
6261 #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0)
6262 #define CATCH_SECTION( ... )
6263 #define CATCH_DYNAMIC_SECTION( ... )
6264 #define CATCH_FAIL( ... ) (void)(0)
6265 #define CATCH_FAIL_CHECK( ... ) (void)(0)
6266 #define CATCH_SUCCEED( ... ) (void)(0)
6267 #define CATCH_SKIP( ... ) (void)(0)
6268
6269 #define CATCH_STATIC_REQUIRE( ... ) (void)(0)
6270 #define CATCH_STATIC_REQUIRE_FALSE( ... ) (void)(0)
6271 #define CATCH_STATIC_CHECK( ... ) (void)(0)
6272 #define CATCH_STATIC_CHECK_FALSE( ... ) (void)(0)
6273
6274 // "BDD-style" convenience wrappers
6275 #define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
6276 #define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
6277 #define CATCH_GIVEN( desc )
6278 #define CATCH_AND_GIVEN( desc )
6279 #define CATCH_WHEN( desc )
6280 #define CATCH_AND_WHEN( desc )
6281 #define CATCH_THEN( desc )
6282 #define CATCH_AND_THEN( desc )
6283
6284#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE) // ^^ prefixed, disabled | vv unprefixed, implemented
6285
6286 #define REQUIRE( ... ) INTERNAL_CATCH_TEST( "REQUIRE", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6287 #define REQUIRE_FALSE( ... ) INTERNAL_CATCH_TEST( "REQUIRE_FALSE", Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
6288
6289 #define REQUIRE_THROWS( ... ) INTERNAL_CATCH_THROWS( "REQUIRE_THROWS", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6290 #define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "REQUIRE_THROWS_AS", exceptionType, Catch::ResultDisposition::Normal, expr )
6291 #define REQUIRE_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "REQUIRE_NOTHROW", Catch::ResultDisposition::Normal, __VA_ARGS__ )
6292
6293 #define CHECK( ... ) INTERNAL_CATCH_TEST( "CHECK", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6294 #define CHECK_FALSE( ... ) INTERNAL_CATCH_TEST( "CHECK_FALSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, __VA_ARGS__ )
6295 #define CHECKED_IF( ... ) INTERNAL_CATCH_IF( "CHECKED_IF", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6296 #define CHECKED_ELSE( ... ) INTERNAL_CATCH_ELSE( "CHECKED_ELSE", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6297 #define CHECK_NOFAIL( ... ) INTERNAL_CATCH_TEST( "CHECK_NOFAIL", Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, __VA_ARGS__ )
6298
6299 #define CHECK_THROWS( ... ) INTERNAL_CATCH_THROWS( "CHECK_THROWS", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6300 #define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( "CHECK_THROWS_AS", exceptionType, Catch::ResultDisposition::ContinueOnFailure, expr )
6301 #define CHECK_NOTHROW( ... ) INTERNAL_CATCH_NO_THROW( "CHECK_NOTHROW", Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6302
6303 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
6304 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
6305 #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
6306 #define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TEST_CASE_PERSISTENT_FIXTURE( className, __VA_ARGS__ )
6307 #define REGISTER_TEST_CASE( Function, ... ) INTERNAL_CATCH_REGISTER_TESTCASE( Function, __VA_ARGS__ )
6308 #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
6309 #define DYNAMIC_SECTION( ... ) INTERNAL_CATCH_DYNAMIC_SECTION( __VA_ARGS__ )
6310 #define FAIL( ... ) INTERNAL_CATCH_MSG( "FAIL", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, __VA_ARGS__ )
6311 #define FAIL_CHECK( ... ) INTERNAL_CATCH_MSG( "FAIL_CHECK", Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6312 #define SUCCEED( ... ) INTERNAL_CATCH_MSG( "SUCCEED", Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, __VA_ARGS__ )
6313 #define SKIP( ... ) INTERNAL_CATCH_MSG( "SKIP", Catch::ResultWas::ExplicitSkip, Catch::ResultDisposition::Normal, __VA_ARGS__ )
6314
6315
6316 #if !defined(CATCH_CONFIG_RUNTIME_STATIC_REQUIRE)
6317 #define STATIC_REQUIRE( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
6318 #define STATIC_REQUIRE_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
6319 #define STATIC_CHECK( ... ) static_assert( __VA_ARGS__, #__VA_ARGS__ ); SUCCEED( #__VA_ARGS__ )
6320 #define STATIC_CHECK_FALSE( ... ) static_assert( !(__VA_ARGS__), "!(" #__VA_ARGS__ ")" ); SUCCEED( "!(" #__VA_ARGS__ ")" )
6321 #else
6322 #define STATIC_REQUIRE( ... ) REQUIRE( __VA_ARGS__ )
6323 #define STATIC_REQUIRE_FALSE( ... ) REQUIRE_FALSE( __VA_ARGS__ )
6324 #define STATIC_CHECK( ... ) CHECK( __VA_ARGS__ )
6325 #define STATIC_CHECK_FALSE( ... ) CHECK_FALSE( __VA_ARGS__ )
6326 #endif
6327
6328 // "BDD-style" convenience wrappers
6329 #define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
6330 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
6331 #define GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Given: " << desc )
6332 #define AND_GIVEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( "And given: " << desc )
6333 #define WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " When: " << desc )
6334 #define AND_WHEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And when: " << desc )
6335 #define THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " Then: " << desc )
6336 #define AND_THEN( desc ) INTERNAL_CATCH_DYNAMIC_SECTION( " And: " << desc )
6337
6338#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE) // ^^ unprefixed, implemented | vv unprefixed, disabled
6339
6340 #define REQUIRE( ... ) (void)(0)
6341 #define REQUIRE_FALSE( ... ) (void)(0)
6342
6343 #define REQUIRE_THROWS( ... ) (void)(0)
6344 #define REQUIRE_THROWS_AS( expr, exceptionType ) (void)(0)
6345 #define REQUIRE_NOTHROW( ... ) (void)(0)
6346
6347 #define CHECK( ... ) (void)(0)
6348 #define CHECK_FALSE( ... ) (void)(0)
6349 #define CHECKED_IF( ... ) if (__VA_ARGS__)
6350 #define CHECKED_ELSE( ... ) if (!(__VA_ARGS__))
6351 #define CHECK_NOFAIL( ... ) (void)(0)
6352
6353 #define CHECK_THROWS( ... ) (void)(0)
6354 #define CHECK_THROWS_AS( expr, exceptionType ) (void)(0)
6355 #define CHECK_NOTHROW( ... ) (void)(0)
6356
6357 #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
6358 #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ))
6359 #define METHOD_AS_TEST_CASE( method, ... )
6360 #define TEST_CASE_PERSISTENT_FIXTURE( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), __VA_ARGS__)
6361 #define REGISTER_TEST_CASE( Function, ... ) (void)(0)
6362 #define SECTION( ... )
6363 #define DYNAMIC_SECTION( ... )
6364 #define FAIL( ... ) (void)(0)
6365 #define FAIL_CHECK( ... ) (void)(0)
6366 #define SUCCEED( ... ) (void)(0)
6367 #define SKIP( ... ) (void)(0)
6368
6369 #define STATIC_REQUIRE( ... ) (void)(0)
6370 #define STATIC_REQUIRE_FALSE( ... ) (void)(0)
6371 #define STATIC_CHECK( ... ) (void)(0)
6372 #define STATIC_CHECK_FALSE( ... ) (void)(0)
6373
6374 // "BDD-style" convenience wrappers
6375 #define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ) )
6376 #define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEST_ ), className )
6377
6378 #define GIVEN( desc )
6379 #define AND_GIVEN( desc )
6380 #define WHEN( desc )
6381 #define AND_WHEN( desc )
6382 #define THEN( desc )
6383 #define AND_THEN( desc )
6384
6385#endif // ^^ unprefixed, disabled
6386
6387// end of user facing macros
6388
6389#endif // CATCH_TEST_MACROS_HPP_INCLUDED
6390
6391
6392#ifndef CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
6393#define CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
6394
6395
6396
6397#ifndef CATCH_PREPROCESSOR_HPP_INCLUDED
6398#define CATCH_PREPROCESSOR_HPP_INCLUDED
6399
6400
6401#if defined(__GNUC__)
6402// We need to silence "empty __VA_ARGS__ warning", and using just _Pragma does not work
6403#pragma GCC system_header
6404#endif
6405
6406
6407#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__
6408#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__)))
6409#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__)))
6410#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__)))
6411#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__)))
6412#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__)))
6413
6414#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6415#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__
6416// MSVC needs more evaluations
6417#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__)))
6418#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__))
6419#else
6420#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__)
6421#endif
6422
6423#define CATCH_REC_END(...)
6424#define CATCH_REC_OUT
6425
6426#define CATCH_EMPTY()
6427#define CATCH_DEFER(id) id CATCH_EMPTY()
6428
6429#define CATCH_REC_GET_END2() 0, CATCH_REC_END
6430#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2
6431#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1
6432#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT
6433#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0)
6434#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next)
6435
6436#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
6437#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ )
6438#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ )
6439
6440#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
6441#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ )
6442#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ )
6443
6444// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results,
6445// and passes userdata as the first parameter to each invocation,
6446// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c)
6447#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
6448
6449#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0))
6450
6451#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__)
6452#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6453#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__
6454#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param))
6455#else
6456// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF
6457#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__)
6458#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__
6459#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1)
6460#endif
6461
6462#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__
6463#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name)
6464
6465#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6466#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>())
6467#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))
6468#else
6469#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS_GEN(__VA_ARGS__)>()))
6470#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)))
6471#endif
6472
6473#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\
6474 CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__)
6475
6476#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0)
6477#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1)
6478#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2)
6479#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3)
6480#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4)
6481#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5)
6482#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6)
6483#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7)
6484#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8)
6485#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9)
6486#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10)
6487
6488#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
6489
6490#define INTERNAL_CATCH_TYPE_GEN\
6491 template<typename...> struct TypeList {};\
6492 template<typename...Ts>\
6493 constexpr auto get_wrapper() noexcept -> TypeList<Ts...> { return {}; }\
6494 template<template<typename...> class...> struct TemplateTypeList{};\
6495 template<template<typename...> class...Cs>\
6496 constexpr auto get_wrapper() noexcept -> TemplateTypeList<Cs...> { return {}; }\
6497 template<typename...>\
6498 struct append;\
6499 template<typename...>\
6500 struct rewrap;\
6501 template<template<typename...> class, typename...>\
6502 struct create;\
6503 template<template<typename...> class, typename>\
6504 struct convert;\
6505 \
6506 template<typename T> \
6507 struct append<T> { using type = T; };\
6508 template< template<typename...> class L1, typename...E1, template<typename...> class L2, typename...E2, typename...Rest>\
6509 struct append<L1<E1...>, L2<E2...>, Rest...> { using type = typename append<L1<E1...,E2...>, Rest...>::type; };\
6510 template< template<typename...> class L1, typename...E1, typename...Rest>\
6511 struct append<L1<E1...>, TypeList<mpl_::na>, Rest...> { using type = L1<E1...>; };\
6512 \
6513 template< template<typename...> class Container, template<typename...> class List, typename...elems>\
6514 struct rewrap<TemplateTypeList<Container>, List<elems...>> { using type = TypeList<Container<elems...>>; };\
6515 template< template<typename...> class Container, template<typename...> class List, class...Elems, typename...Elements>\
6516 struct rewrap<TemplateTypeList<Container>, List<Elems...>, Elements...> { using type = typename append<TypeList<Container<Elems...>>, typename rewrap<TemplateTypeList<Container>, Elements...>::type>::type; };\
6517 \
6518 template<template <typename...> class Final, template< typename...> class...Containers, typename...Types>\
6519 struct create<Final, TemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<TemplateTypeList<Containers>, Types...>::type...>::type; };\
6520 template<template <typename...> class Final, template <typename...> class List, typename...Ts>\
6521 struct convert<Final, List<Ts...>> { using type = typename append<Final<>,TypeList<Ts>...>::type; };
6522
6523#define INTERNAL_CATCH_NTTP_1(signature, ...)\
6524 template<INTERNAL_CATCH_REMOVE_PARENS(signature)> struct Nttp{};\
6525 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6526 constexpr auto get_wrapper() noexcept -> Nttp<__VA_ARGS__> { return {}; } \
6527 template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...> struct NttpTemplateTypeList{};\
6528 template<template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Cs>\
6529 constexpr auto get_wrapper() noexcept -> NttpTemplateTypeList<Cs...> { return {}; } \
6530 \
6531 template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6532 struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>> { using type = TypeList<Container<__VA_ARGS__>>; };\
6533 template< template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class Container, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class List, INTERNAL_CATCH_REMOVE_PARENS(signature), typename...Elements>\
6534 struct rewrap<NttpTemplateTypeList<Container>, List<__VA_ARGS__>, Elements...> { using type = typename append<TypeList<Container<__VA_ARGS__>>, typename rewrap<NttpTemplateTypeList<Container>, Elements...>::type>::type; };\
6535 template<template <typename...> class Final, template<INTERNAL_CATCH_REMOVE_PARENS(signature)> class...Containers, typename...Types>\
6536 struct create<Final, NttpTemplateTypeList<Containers...>, TypeList<Types...>> { using type = typename append<Final<>, typename rewrap<NttpTemplateTypeList<Containers>, Types...>::type...>::type; };
6537
6538#define INTERNAL_CATCH_DECLARE_SIG_TEST0(TestName)
6539#define INTERNAL_CATCH_DECLARE_SIG_TEST1(TestName, signature)\
6540 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6541 static void TestName()
6542#define INTERNAL_CATCH_DECLARE_SIG_TEST_X(TestName, signature, ...)\
6543 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6544 static void TestName()
6545
6546#define INTERNAL_CATCH_DEFINE_SIG_TEST0(TestName)
6547#define INTERNAL_CATCH_DEFINE_SIG_TEST1(TestName, signature)\
6548 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6549 static void TestName()
6550#define INTERNAL_CATCH_DEFINE_SIG_TEST_X(TestName, signature,...)\
6551 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6552 static void TestName()
6553
6554#define INTERNAL_CATCH_NTTP_REGISTER0(TestFunc, signature)\
6555 template<typename Type>\
6556 void reg_test(TypeList<Type>, Catch::NameAndTags nameAndTags)\
6557 {\
6558 Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<Type>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
6559 }
6560
6561#define INTERNAL_CATCH_NTTP_REGISTER(TestFunc, signature, ...)\
6562 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6563 void reg_test(Nttp<__VA_ARGS__>, Catch::NameAndTags nameAndTags)\
6564 {\
6565 Catch::AutoReg( Catch::makeTestInvoker(&TestFunc<__VA_ARGS__>), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), nameAndTags);\
6566 }
6567
6568#define INTERNAL_CATCH_NTTP_REGISTER_METHOD0(TestName, signature, ...)\
6569 template<typename Type>\
6570 void reg_test(TypeList<Type>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
6571 {\
6572 Catch::AutoReg( Catch::makeTestInvoker(&TestName<Type>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
6573 }
6574
6575#define INTERNAL_CATCH_NTTP_REGISTER_METHOD(TestName, signature, ...)\
6576 template<INTERNAL_CATCH_REMOVE_PARENS(signature)>\
6577 void reg_test(Nttp<__VA_ARGS__>, Catch::StringRef className, Catch::NameAndTags nameAndTags)\
6578 {\
6579 Catch::AutoReg( Catch::makeTestInvoker(&TestName<__VA_ARGS__>::test), CATCH_INTERNAL_LINEINFO, className, nameAndTags);\
6580 }
6581
6582#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0(TestName, ClassName)
6583#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1(TestName, ClassName, signature)\
6584 template<typename TestType> \
6585 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<TestType> { \
6586 void test();\
6587 }
6588
6589#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X(TestName, ClassName, signature, ...)\
6590 template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
6591 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName)<__VA_ARGS__> { \
6592 void test();\
6593 }
6594
6595#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0(TestName)
6596#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1(TestName, signature)\
6597 template<typename TestType> \
6598 void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<TestType>::test()
6599#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X(TestName, signature, ...)\
6600 template<INTERNAL_CATCH_REMOVE_PARENS(signature)> \
6601 void INTERNAL_CATCH_MAKE_NAMESPACE(TestName)::TestName<__VA_ARGS__>::test()
6602
6603#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6604#define INTERNAL_CATCH_NTTP_0
6605#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1(__VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_1( __VA_ARGS__),INTERNAL_CATCH_NTTP_1( __VA_ARGS__), INTERNAL_CATCH_NTTP_0)
6606#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__)
6607#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__)
6608#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__)
6609#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__)
6610#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__)
6611#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__)
6612#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__)
6613#else
6614#define INTERNAL_CATCH_NTTP_0(signature)
6615#define INTERNAL_CATCH_NTTP_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_1,INTERNAL_CATCH_NTTP_1, INTERNAL_CATCH_NTTP_0)( __VA_ARGS__))
6616#define INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD1, INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD0)(TestName, __VA_ARGS__))
6617#define INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X,INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD_X, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD1, INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD0)(TestName, ClassName, __VA_ARGS__))
6618#define INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD, INTERNAL_CATCH_NTTP_REGISTER_METHOD0, INTERNAL_CATCH_NTTP_REGISTER_METHOD0)(TestName, __VA_ARGS__))
6619#define INTERNAL_CATCH_NTTP_REG_GEN(TestFunc, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER, INTERNAL_CATCH_NTTP_REGISTER0, INTERNAL_CATCH_NTTP_REGISTER0)(TestFunc, __VA_ARGS__))
6620#define INTERNAL_CATCH_DEFINE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DEFINE_SIG_TEST1, INTERNAL_CATCH_DEFINE_SIG_TEST0)(TestName, __VA_ARGS__))
6621#define INTERNAL_CATCH_DECLARE_SIG_TEST(TestName, ...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL( "dummy", __VA_ARGS__, INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DEFINE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X,INTERNAL_CATCH_DECLARE_SIG_TEST_X, INTERNAL_CATCH_DECLARE_SIG_TEST1, INTERNAL_CATCH_DECLARE_SIG_TEST0)(TestName, __VA_ARGS__))
6622#define INTERNAL_CATCH_REMOVE_PARENS_GEN(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_VA_NARGS_IMPL(__VA_ARGS__, INTERNAL_CATCH_REMOVE_PARENS_11_ARG,INTERNAL_CATCH_REMOVE_PARENS_10_ARG,INTERNAL_CATCH_REMOVE_PARENS_9_ARG,INTERNAL_CATCH_REMOVE_PARENS_8_ARG,INTERNAL_CATCH_REMOVE_PARENS_7_ARG,INTERNAL_CATCH_REMOVE_PARENS_6_ARG,INTERNAL_CATCH_REMOVE_PARENS_5_ARG,INTERNAL_CATCH_REMOVE_PARENS_4_ARG,INTERNAL_CATCH_REMOVE_PARENS_3_ARG,INTERNAL_CATCH_REMOVE_PARENS_2_ARG,INTERNAL_CATCH_REMOVE_PARENS_1_ARG)(__VA_ARGS__))
6623#endif
6624
6625#endif // CATCH_PREPROCESSOR_HPP_INCLUDED
6626
6627
6628// GCC 5 and older do not properly handle disabling unused-variable warning
6629// with a _Pragma. This means that we have to leak the suppression to the
6630// user code as well :-(
6631#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ <= 5
6632#pragma GCC diagnostic ignored "-Wunused-variable"
6633#endif
6634
6635#if defined(CATCH_CONFIG_DISABLE)
6636 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( TestName, TestFunc, Name, Tags, Signature, ... ) \
6637 INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature))
6638 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
6639 namespace{ \
6640 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
6641 INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
6642 } \
6643 } \
6644 INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
6645
6646 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6647 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
6648 INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
6649 #else
6650 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \
6651 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
6652 #endif
6653
6654 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6655 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
6656 INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
6657 #else
6658 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \
6659 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
6660 #endif
6661
6662 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6663 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
6664 INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
6665 #else
6666 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \
6667 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
6668 #endif
6669
6670 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6671 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
6672 INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
6673 #else
6674 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \
6675 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
6676 #endif
6677#endif
6678
6679
6680 ///////////////////////////////////////////////////////////////////////////////
6681 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_2(TestName, TestFunc, Name, Tags, Signature, ... )\
6682 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6683 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6684 CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
6685 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6686 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6687 CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
6688 INTERNAL_CATCH_DECLARE_SIG_TEST(TestFunc, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
6689 namespace {\
6690 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
6691 INTERNAL_CATCH_TYPE_GEN\
6692 INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
6693 INTERNAL_CATCH_NTTP_REG_GEN(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))\
6694 template<typename...Types> \
6695 struct TestName{\
6696 TestName(){\
6697 size_t index = 0; \
6698 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)}; /* NOLINT(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-avoid-c-arrays) */\
6699 using expander = size_t[]; /* NOLINT(cppcoreguidelines-avoid-c-arrays,modernize-avoid-c-arrays,hicpp-avoid-c-arrays) */\
6700 (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
6701 }\
6702 };\
6703 static const int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
6704 TestName<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
6705 return 0;\
6706 }();\
6707 }\
6708 }\
6709 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6710 INTERNAL_CATCH_DEFINE_SIG_TEST(TestFunc,INTERNAL_CATCH_REMOVE_PARENS(Signature))
6711
6712#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6713 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
6714 INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ )
6715#else
6716 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \
6717 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename TestType, __VA_ARGS__ ) )
6718#endif
6719
6720#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6721 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
6722 INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ )
6723#else
6724 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \
6725 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
6726#endif
6727
6728 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \
6729 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6730 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6731 CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
6732 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6733 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6734 CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
6735 template<typename TestType> static void TestFuncName(); \
6736 namespace {\
6737 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName) { \
6738 INTERNAL_CATCH_TYPE_GEN \
6739 INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature)) \
6740 template<typename... Types> \
6741 struct TestName { \
6742 void reg_tests() { \
6743 size_t index = 0; \
6744 using expander = size_t[]; \
6745 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
6746 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
6747 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
6748 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */\
6749 } \
6750 }; \
6751 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
6752 using TestInit = typename create<TestName, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type; \
6753 TestInit t; \
6754 t.reg_tests(); \
6755 return 0; \
6756 }(); \
6757 } \
6758 } \
6759 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6760 template<typename TestType> \
6761 static void TestFuncName()
6762
6763#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6764 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
6765 INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T,__VA_ARGS__)
6766#else
6767 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\
6768 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, typename T, __VA_ARGS__ ) )
6769#endif
6770
6771#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6772 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
6773 INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__)
6774#else
6775 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\
6776 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, Signature, __VA_ARGS__ ) )
6777#endif
6778
6779 #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\
6780 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6781 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6782 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6783 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6784 CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
6785 template<typename TestType> static void TestFunc(); \
6786 namespace {\
6787 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){\
6788 INTERNAL_CATCH_TYPE_GEN\
6789 template<typename... Types> \
6790 struct TestName { \
6791 void reg_tests() { \
6792 size_t index = 0; \
6793 using expander = size_t[]; \
6794 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc<Types> ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\
6795 } \
6796 };\
6797 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \
6798 using TestInit = typename convert<TestName, TmplList>::type; \
6799 TestInit t; \
6800 t.reg_tests(); \
6801 return 0; \
6802 }(); \
6803 }}\
6804 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6805 template<typename TestType> \
6806 static void TestFunc()
6807
6808 #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \
6809 INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), Name, Tags, TmplList )
6810
6811
6812 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \
6813 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6814 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6815 CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
6816 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6817 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6818 namespace {\
6819 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
6820 INTERNAL_CATCH_TYPE_GEN\
6821 INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
6822 INTERNAL_CATCH_DECLARE_SIG_TEST_METHOD(TestName, ClassName, INTERNAL_CATCH_REMOVE_PARENS(Signature));\
6823 INTERNAL_CATCH_NTTP_REG_METHOD_GEN(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))\
6824 template<typename...Types> \
6825 struct TestNameClass{\
6826 TestNameClass(){\
6827 size_t index = 0; \
6828 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\
6829 using expander = size_t[];\
6830 (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \
6831 }\
6832 };\
6833 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
6834 TestNameClass<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(__VA_ARGS__)>();\
6835 return 0;\
6836 }();\
6837 }\
6838 }\
6839 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6840 INTERNAL_CATCH_DEFINE_SIG_TEST_METHOD(TestName, INTERNAL_CATCH_REMOVE_PARENS(Signature))
6841
6842#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6843 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
6844 INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ )
6845#else
6846 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \
6847 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) )
6848#endif
6849
6850#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6851 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
6852 INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ )
6853#else
6854 #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \
6855 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_CLASS_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) )
6856#endif
6857
6858 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\
6859 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6860 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6861 CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \
6862 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6863 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6864 template<typename TestType> \
6865 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
6866 void test();\
6867 };\
6868 namespace {\
6869 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestNameClass) {\
6870 INTERNAL_CATCH_TYPE_GEN \
6871 INTERNAL_CATCH_NTTP_GEN(INTERNAL_CATCH_REMOVE_PARENS(Signature))\
6872 template<typename...Types>\
6873 struct TestNameClass{\
6874 void reg_tests(){\
6875 std::size_t index = 0;\
6876 using expander = std::size_t[];\
6877 constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\
6878 constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\
6879 constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\
6880 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + '<' + std::string(types_list[index % num_types]) + '>', Tags } ), index++)... };/* NOLINT */ \
6881 }\
6882 };\
6883 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
6884 using TestInit = typename create<TestNameClass, decltype(get_wrapper<INTERNAL_CATCH_REMOVE_PARENS(TmplTypes)>()), TypeList<INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(INTERNAL_CATCH_REMOVE_PARENS(TypesList))>>::type;\
6885 TestInit t;\
6886 t.reg_tests();\
6887 return 0;\
6888 }(); \
6889 }\
6890 }\
6891 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6892 template<typename TestType> \
6893 void TestName<TestType>::test()
6894
6895#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6896 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
6897 INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ )
6898#else
6899 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\
6900 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) )
6901#endif
6902
6903#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6904 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
6905 INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ )
6906#else
6907 #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\
6908 INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) )
6909#endif
6910
6911 #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \
6912 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
6913 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
6914 CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \
6915 CATCH_INTERNAL_SUPPRESS_UNUSED_VARIABLE_WARNINGS \
6916 CATCH_INTERNAL_SUPPRESS_COMMA_WARNINGS \
6917 template<typename TestType> \
6918 struct TestName : INTERNAL_CATCH_REMOVE_PARENS(ClassName <TestType>) { \
6919 void test();\
6920 };\
6921 namespace {\
6922 namespace INTERNAL_CATCH_MAKE_NAMESPACE(TestName){ \
6923 INTERNAL_CATCH_TYPE_GEN\
6924 template<typename...Types>\
6925 struct TestNameClass{\
6926 void reg_tests(){\
6927 size_t index = 0;\
6928 using expander = size_t[];\
6929 (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName<Types>::test ), CATCH_INTERNAL_LINEINFO, #ClassName##_catch_sr, Catch::NameAndTags{ Name " - " INTERNAL_CATCH_STRINGIZE(TmplList) " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \
6930 }\
6931 };\
6932 static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\
6933 using TestInit = typename convert<TestNameClass, TmplList>::type;\
6934 TestInit t;\
6935 t.reg_tests();\
6936 return 0;\
6937 }(); \
6938 }}\
6939 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
6940 template<typename TestType> \
6941 void TestName<TestType>::test()
6942
6943#define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \
6944 INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), INTERNAL_CATCH_UNIQUE_NAME( CATCH2_INTERNAL_TEMPLATE_TEST_ ), ClassName, Name, Tags, TmplList )
6945
6946
6947#endif // CATCH_TEMPLATE_TEST_REGISTRY_HPP_INCLUDED
6948
6949
6950#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
6951
6952 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6953 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
6954 #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
6955 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
6956 #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
6957 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
6958 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
6959 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
6960 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
6961 #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
6962 #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
6963 #else
6964 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
6965 #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
6966 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
6967 #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
6968 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
6969 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
6970 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
6971 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
6972 #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
6973 #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
6974 #endif
6975
6976#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
6977
6978 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
6979 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
6980 #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
6981 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
6982 #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
6983 #else
6984 #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
6985 #define CATCH_TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
6986 #define CATCH_TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
6987 #define CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
6988 #endif
6989
6990 // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
6991 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
6992 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
6993 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
6994 #define CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
6995 #define CATCH_TEMPLATE_LIST_TEST_CASE( ... ) CATCH_TEMPLATE_TEST_CASE(__VA_ARGS__)
6996 #define CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
6997
6998#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
6999
7000 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
7001 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ )
7002 #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ )
7003 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
7004 #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
7005 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ )
7006 #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ )
7007 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ )
7008 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ )
7009 #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(__VA_ARGS__)
7010 #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ )
7011 #else
7012 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE( __VA_ARGS__ ) )
7013 #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG( __VA_ARGS__ ) )
7014 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
7015 #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
7016 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE( __VA_ARGS__ ) )
7017 #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG( __VA_ARGS__ ) )
7018 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
7019 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, __VA_ARGS__ ) )
7020 #define TEMPLATE_LIST_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE( __VA_ARGS__ ) )
7021 #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD( className, __VA_ARGS__ ) )
7022 #endif
7023
7024#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
7025
7026 #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR
7027 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__)
7028 #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__)
7029 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__)
7030 #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ )
7031 #else
7032 #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) )
7033 #define TEMPLATE_TEST_CASE_SIG( ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(__VA_ARGS__) )
7034 #define TEMPLATE_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION(className, __VA_ARGS__ ) )
7035 #define TEMPLATE_TEST_CASE_METHOD_SIG( className, ... ) INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION(className, __VA_ARGS__ ) )
7036 #endif
7037
7038 // When disabled, these can be shared between proper preprocessor and MSVC preprocessor
7039 #define TEMPLATE_PRODUCT_TEST_CASE( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
7040 #define TEMPLATE_PRODUCT_TEST_CASE_SIG( ... ) TEMPLATE_TEST_CASE( __VA_ARGS__ )
7041 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
7042 #define TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
7043 #define TEMPLATE_LIST_TEST_CASE( ... ) TEMPLATE_TEST_CASE(__VA_ARGS__)
7044 #define TEMPLATE_LIST_TEST_CASE_METHOD( className, ... ) TEMPLATE_TEST_CASE_METHOD( className, __VA_ARGS__ )
7045
7046#endif // end of user facing macro declarations
7047
7048
7049#endif // CATCH_TEMPLATE_TEST_MACROS_HPP_INCLUDED
7050
7051
7052#ifndef CATCH_TEST_CASE_INFO_HPP_INCLUDED
7053#define CATCH_TEST_CASE_INFO_HPP_INCLUDED
7054
7055
7056
7057#include <cstdint>
7058#include <string>
7059#include <vector>
7060
7061#ifdef __clang__
7062#pragma clang diagnostic push
7063#pragma clang diagnostic ignored "-Wpadded"
7064#endif
7065
7066namespace Catch {
7067
7068 /**
7069 * A **view** of a tag string that provides case insensitive comparisons
7070 *
7071 * Note that in Catch2 internals, the square brackets around tags are
7072 * not a part of tag's representation, so e.g. "[cool-tag]" is represented
7073 * as "cool-tag" internally.
7074 */
7075 struct Tag {
7076 constexpr Tag(StringRef original_):
7077 original(original_)
7078 {}
7079 StringRef original;
7080
7081 friend bool operator< ( Tag const& lhs, Tag const& rhs );
7082 friend bool operator==( Tag const& lhs, Tag const& rhs );
7083 };
7084
7085 class ITestInvoker;
7086 struct NameAndTags;
7087
7088 enum class TestCaseProperties : uint8_t {
7089 None = 0,
7090 IsHidden = 1 << 1,
7091 ShouldFail = 1 << 2,
7092 MayFail = 1 << 3,
7093 Throws = 1 << 4,
7094 NonPortable = 1 << 5,
7095 Benchmark = 1 << 6
7096 };
7097
7098 /**
7099 * Various metadata about the test case.
7100 *
7101 * A test case is uniquely identified by its (class)name and tags
7102 * combination, with source location being ignored, and other properties
7103 * being determined from tags.
7104 *
7105 * Tags are kept sorted.
7106 */
7107 struct TestCaseInfo : Detail::NonCopyable {
7108
7109 TestCaseInfo(StringRef _className,
7110 NameAndTags const& _nameAndTags,
7111 SourceLineInfo const& _lineInfo);
7112
7113 bool isHidden() const;
7114 bool throws() const;
7115 bool okToFail() const;
7116 bool expectedToFail() const;
7117
7118 // Adds the tag(s) with test's filename (for the -# flag)
7119 void addFilenameTag();
7120
7121 //! Orders by name, classname and tags
7122 friend bool operator<( TestCaseInfo const& lhs,
7123 TestCaseInfo const& rhs );
7124
7125
7126 std::string tagsAsString() const;
7127
7128 std::string name;
7129 StringRef className;
7130 private:
7131 std::string backingTags;
7132 // Internally we copy tags to the backing storage and then add
7133 // refs to this storage to the tags vector.
7134 void internalAppendTag(StringRef tagString);
7135 public:
7136 std::vector<Tag> tags;
7137 SourceLineInfo lineInfo;
7138 TestCaseProperties properties = TestCaseProperties::None;
7139 };
7140
7141 /**
7142 * Wrapper over the test case information and the test case invoker
7143 *
7144 * Does not own either, and is specifically made to be cheap
7145 * to copy around.
7146 */
7147 class TestCaseHandle {
7148 TestCaseInfo* m_info;
7149 ITestInvoker* m_invoker;
7150 public:
7151 constexpr TestCaseHandle(TestCaseInfo* info, ITestInvoker* invoker) :
7152 m_info(info), m_invoker(invoker) {}
7153
7154 void prepareTestCase() const {
7155 m_invoker->prepareTestCase();
7156 }
7157
7158 void tearDownTestCase() const {
7159 m_invoker->tearDownTestCase();
7160 }
7161
7162 void invoke() const {
7163 m_invoker->invoke();
7164 }
7165
7166 constexpr TestCaseInfo const& getTestCaseInfo() const {
7167 return *m_info;
7168 }
7169 };
7170
7171 Detail::unique_ptr<TestCaseInfo>
7172 makeTestCaseInfo( StringRef className,
7173 NameAndTags const& nameAndTags,
7174 SourceLineInfo const& lineInfo );
7175}
7176
7177#ifdef __clang__
7178#pragma clang diagnostic pop
7179#endif
7180
7181#endif // CATCH_TEST_CASE_INFO_HPP_INCLUDED
7182
7183
7184#ifndef CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
7185#define CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
7186
7187
7188
7189#ifndef CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
7190#define CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
7191
7192
7193#include <string>
7194#include <vector>
7195
7196namespace Catch {
7197 using exceptionTranslateFunction = std::string(*)();
7198
7199 class IExceptionTranslator;
7200 using ExceptionTranslators = std::vector<Detail::unique_ptr<IExceptionTranslator const>>;
7201
7202 class IExceptionTranslator {
7203 public:
7204 virtual ~IExceptionTranslator(); // = default
7205 virtual std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const = 0;
7206 };
7207
7208 class IExceptionTranslatorRegistry {
7209 public:
7210 virtual ~IExceptionTranslatorRegistry(); // = default
7211 virtual std::string translateActiveException() const = 0;
7212 };
7213
7214} // namespace Catch
7215
7216#endif // CATCH_INTERFACES_EXCEPTION_HPP_INCLUDED
7217
7218#include <exception>
7219
7220namespace Catch {
7221 namespace Detail {
7222 void registerTranslatorImpl(
7223 Detail::unique_ptr<IExceptionTranslator>&& translator );
7224 }
7225
7226 class ExceptionTranslatorRegistrar {
7227 template<typename T>
7228 class ExceptionTranslator : public IExceptionTranslator {
7229 public:
7230
7231 constexpr ExceptionTranslator( std::string(*translateFunction)( T const& ) )
7232 : m_translateFunction( translateFunction )
7233 {}
7234
7235 std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override {
7236#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
7237 try {
7238 if( it == itEnd )
7239 std::rethrow_exception(std::current_exception());
7240 else
7241 return (*it)->translate( it+1, itEnd );
7242 }
7243 catch( T const& ex ) {
7244 return m_translateFunction( ex );
7245 }
7246#else
7247 return "You should never get here!";
7248#endif
7249 }
7250
7251 protected:
7252 std::string(*m_translateFunction)( T const& );
7253 };
7254
7255 public:
7256 template<typename T>
7257 ExceptionTranslatorRegistrar( std::string(*translateFunction)( T const& ) ) {
7258 Detail::registerTranslatorImpl(
7259 Detail::make_unique<ExceptionTranslator<T>>(
7260 translateFunction ) );
7261 }
7262 };
7263
7264} // namespace Catch
7265
7266///////////////////////////////////////////////////////////////////////////////
7267#define INTERNAL_CATCH_TRANSLATE_EXCEPTION2( translatorName, signature ) \
7268 static std::string translatorName( signature ); \
7269 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
7270 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
7271 namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &translatorName ); } \
7272 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
7273 static std::string translatorName( signature )
7274
7275#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION2( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
7276
7277#if defined(CATCH_CONFIG_DISABLE)
7278 #define INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( translatorName, signature) \
7279 static std::string translatorName( signature )
7280#endif
7281
7282
7283// This macro is always prefixed
7284#if !defined(CATCH_CONFIG_DISABLE)
7285#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
7286#else
7287#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature )
7288#endif
7289
7290
7291#endif // CATCH_TRANSLATE_EXCEPTION_HPP_INCLUDED
7292
7293
7294#ifndef CATCH_VERSION_HPP_INCLUDED
7295#define CATCH_VERSION_HPP_INCLUDED
7296
7297#include <iosfwd>
7298
7299namespace Catch {
7300
7301 // Versioning information
7302 struct Version {
7303 Version( Version const& ) = delete;
7304 Version& operator=( Version const& ) = delete;
7305 Version( unsigned int _majorVersion,
7306 unsigned int _minorVersion,
7307 unsigned int _patchNumber,
7308 char const * const _branchName,
7309 unsigned int _buildNumber );
7310
7311 unsigned int const majorVersion;
7312 unsigned int const minorVersion;
7313 unsigned int const patchNumber;
7314
7315 // buildNumber is only used if branchName is not null
7316 char const * const branchName;
7317 unsigned int const buildNumber;
7318
7319 friend std::ostream& operator << ( std::ostream& os, Version const& version );
7320 };
7321
7322 Version const& libraryVersion();
7323}
7324
7325#endif // CATCH_VERSION_HPP_INCLUDED
7326
7327
7328#ifndef CATCH_VERSION_MACROS_HPP_INCLUDED
7329#define CATCH_VERSION_MACROS_HPP_INCLUDED
7330
7331#define CATCH_VERSION_MAJOR 3
7332#define CATCH_VERSION_MINOR 7
7333#define CATCH_VERSION_PATCH 1
7334
7335#endif // CATCH_VERSION_MACROS_HPP_INCLUDED
7336
7337
7338/** \file
7339 * This is a convenience header for Catch2's Generator support. It includes
7340 * **all** of Catch2 headers related to generators.
7341 *
7342 * Generally the Catch2 users should use specific includes they need,
7343 * but this header can be used instead for ease-of-experimentation, or
7344 * just plain convenience, at the cost of (significantly) increased
7345 * compilation times.
7346 *
7347 * When a new header is added to either the `generators` folder,
7348 * or to the corresponding internal subfolder, it should be added here.
7349 */
7350
7351#ifndef CATCH_GENERATORS_ALL_HPP_INCLUDED
7352#define CATCH_GENERATORS_ALL_HPP_INCLUDED
7353
7354
7355
7356#ifndef CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
7357#define CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
7358
7359#include <exception>
7360
7361namespace Catch {
7362
7363 // Exception type to be thrown when a Generator runs into an error,
7364 // e.g. it cannot initialize the first return value based on
7365 // runtime information
7366 class GeneratorException : public std::exception {
7367 const char* const m_msg = "";
7368
7369 public:
7370 GeneratorException(const char* msg):
7371 m_msg(msg)
7372 {}
7373
7374 const char* what() const noexcept override final;
7375 };
7376
7377} // end namespace Catch
7378
7379#endif // CATCH_GENERATOR_EXCEPTION_HPP_INCLUDED
7380
7381
7382#ifndef CATCH_GENERATORS_HPP_INCLUDED
7383#define CATCH_GENERATORS_HPP_INCLUDED
7384
7385
7386
7387#ifndef CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
7388#define CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
7389
7390
7391#include <string>
7392
7393namespace Catch {
7394
7395 namespace Generators {
7396 class GeneratorUntypedBase {
7397 // Caches result from `toStringImpl`, assume that when it is an
7398 // empty string, the cache is invalidated.
7399 mutable std::string m_stringReprCache;
7400
7401 // Counts based on `next` returning true
7402 std::size_t m_currentElementIndex = 0;
7403
7404 /**
7405 * Attempts to move the generator to the next element
7406 *
7407 * Returns true iff the move succeeded (and a valid element
7408 * can be retrieved).
7409 */
7410 virtual bool next() = 0;
7411
7412 //! Customization point for `currentElementAsString`
7413 virtual std::string stringifyImpl() const = 0;
7414
7415 public:
7416 GeneratorUntypedBase() = default;
7417 // Generation of copy ops is deprecated (and Clang will complain)
7418 // if there is a user destructor defined
7419 GeneratorUntypedBase(GeneratorUntypedBase const&) = default;
7420 GeneratorUntypedBase& operator=(GeneratorUntypedBase const&) = default;
7421
7422 virtual ~GeneratorUntypedBase(); // = default;
7423
7424 /**
7425 * Attempts to move the generator to the next element
7426 *
7427 * Serves as a non-virtual interface to `next`, so that the
7428 * top level interface can provide sanity checking and shared
7429 * features.
7430 *
7431 * As with `next`, returns true iff the move succeeded and
7432 * the generator has new valid element to provide.
7433 */
7434 bool countedNext();
7435
7436 std::size_t currentElementIndex() const { return m_currentElementIndex; }
7437
7438 /**
7439 * Returns generator's current element as user-friendly string.
7440 *
7441 * By default returns string equivalent to calling
7442 * `Catch::Detail::stringify` on the current element, but generators
7443 * can customize their implementation as needed.
7444 *
7445 * Not thread-safe due to internal caching.
7446 *
7447 * The returned ref is valid only until the generator instance
7448 * is destructed, or it moves onto the next element, whichever
7449 * comes first.
7450 */
7451 StringRef currentElementAsString() const;
7452 };
7453 using GeneratorBasePtr = Catch::Detail::unique_ptr<GeneratorUntypedBase>;
7454
7455 } // namespace Generators
7456
7457 class IGeneratorTracker {
7458 public:
7459 virtual ~IGeneratorTracker(); // = default;
7460 virtual auto hasGenerator() const -> bool = 0;
7461 virtual auto getGenerator() const -> Generators::GeneratorBasePtr const& = 0;
7462 virtual void setGenerator( Generators::GeneratorBasePtr&& generator ) = 0;
7463 };
7464
7465} // namespace Catch
7466
7467#endif // CATCH_INTERFACES_GENERATORTRACKER_HPP_INCLUDED
7468
7469#include <vector>
7470#include <tuple>
7471
7472namespace Catch {
7473
7474namespace Generators {
7475
7476namespace Detail {
7477
7478 //! Throws GeneratorException with the provided message
7479 [[noreturn]]
7480 void throw_generator_exception(char const * msg);
7481
7482} // end namespace detail
7483
7484 template<typename T>
7485 class IGenerator : public GeneratorUntypedBase {
7486 std::string stringifyImpl() const override {
7487 return ::Catch::Detail::stringify( get() );
7488 }
7489
7490 public:
7491 // Returns the current element of the generator
7492 //
7493 // \Precondition The generator is either freshly constructed,
7494 // or the last call to `next()` returned true
7495 virtual T const& get() const = 0;
7496 using type = T;
7497 };
7498
7499 template <typename T>
7500 using GeneratorPtr = Catch::Detail::unique_ptr<IGenerator<T>>;
7501
7502 template <typename T>
7503 class GeneratorWrapper final {
7504 GeneratorPtr<T> m_generator;
7505 public:
7506 //! Takes ownership of the passed pointer.
7507 GeneratorWrapper(IGenerator<T>* generator):
7508 m_generator(generator) {}
7509 GeneratorWrapper(GeneratorPtr<T> generator):
7510 m_generator(CATCH_MOVE(generator)) {}
7511
7512 T const& get() const {
7513 return m_generator->get();
7514 }
7515 bool next() {
7516 return m_generator->countedNext();
7517 }
7518 };
7519
7520
7521 template<typename T>
7522 class SingleValueGenerator final : public IGenerator<T> {
7523 T m_value;
7524 public:
7525 SingleValueGenerator(T const& value) :
7526 m_value(value)
7527 {}
7528 SingleValueGenerator(T&& value):
7529 m_value(CATCH_MOVE(value))
7530 {}
7531
7532 T const& get() const override {
7533 return m_value;
7534 }
7535 bool next() override {
7536 return false;
7537 }
7538 };
7539
7540 template<typename T>
7541 class FixedValuesGenerator final : public IGenerator<T> {
7542 static_assert(!std::is_same<T, bool>::value,
7543 "FixedValuesGenerator does not support bools because of std::vector<bool>"
7544 "specialization, use SingleValue Generator instead.");
7545 std::vector<T> m_values;
7546 size_t m_idx = 0;
7547 public:
7548 FixedValuesGenerator( std::initializer_list<T> values ) : m_values( values ) {}
7549
7550 T const& get() const override {
7551 return m_values[m_idx];
7552 }
7553 bool next() override {
7554 ++m_idx;
7555 return m_idx < m_values.size();
7556 }
7557 };
7558
7559 template <typename T, typename DecayedT = std::decay_t<T>>
7560 GeneratorWrapper<DecayedT> value( T&& value ) {
7561 return GeneratorWrapper<DecayedT>(
7562 Catch::Detail::make_unique<SingleValueGenerator<DecayedT>>(
7563 CATCH_FORWARD( value ) ) );
7564 }
7565 template <typename T>
7566 GeneratorWrapper<T> values(std::initializer_list<T> values) {
7567 return GeneratorWrapper<T>(Catch::Detail::make_unique<FixedValuesGenerator<T>>(values));
7568 }
7569
7570 template<typename T>
7571 class Generators : public IGenerator<T> {
7572 std::vector<GeneratorWrapper<T>> m_generators;
7573 size_t m_current = 0;
7574
7575 void add_generator( GeneratorWrapper<T>&& generator ) {
7576 m_generators.emplace_back( CATCH_MOVE( generator ) );
7577 }
7578 void add_generator( T const& val ) {
7579 m_generators.emplace_back( value( val ) );
7580 }
7581 void add_generator( T&& val ) {
7582 m_generators.emplace_back( value( CATCH_MOVE( val ) ) );
7583 }
7584 template <typename U>
7585 std::enable_if_t<!std::is_same<std::decay_t<U>, T>::value>
7586 add_generator( U&& val ) {
7587 add_generator( T( CATCH_FORWARD( val ) ) );
7588 }
7589
7590 template <typename U> void add_generators( U&& valueOrGenerator ) {
7591 add_generator( CATCH_FORWARD( valueOrGenerator ) );
7592 }
7593
7594 template <typename U, typename... Gs>
7595 void add_generators( U&& valueOrGenerator, Gs&&... moreGenerators ) {
7596 add_generator( CATCH_FORWARD( valueOrGenerator ) );
7597 add_generators( CATCH_FORWARD( moreGenerators )... );
7598 }
7599
7600 public:
7601 template <typename... Gs>
7602 Generators(Gs &&... moreGenerators) {
7603 m_generators.reserve(sizeof...(Gs));
7604 add_generators(CATCH_FORWARD(moreGenerators)...);
7605 }
7606
7607 T const& get() const override {
7608 return m_generators[m_current].get();
7609 }
7610
7611 bool next() override {
7612 if (m_current >= m_generators.size()) {
7613 return false;
7614 }
7615 const bool current_status = m_generators[m_current].next();
7616 if (!current_status) {
7617 ++m_current;
7618 }
7619 return m_current < m_generators.size();
7620 }
7621 };
7622
7623
7624 template <typename... Ts>
7625 GeneratorWrapper<std::tuple<std::decay_t<Ts>...>>
7626 table( std::initializer_list<std::tuple<std::decay_t<Ts>...>> tuples ) {
7627 return values<std::tuple<Ts...>>( tuples );
7628 }
7629
7630 // Tag type to signal that a generator sequence should convert arguments to a specific type
7631 template <typename T>
7632 struct as {};
7633
7634 template<typename T, typename... Gs>
7635 auto makeGenerators( GeneratorWrapper<T>&& generator, Gs &&... moreGenerators ) -> Generators<T> {
7636 return Generators<T>(CATCH_MOVE(generator), CATCH_FORWARD(moreGenerators)...);
7637 }
7638 template<typename T>
7639 auto makeGenerators( GeneratorWrapper<T>&& generator ) -> Generators<T> {
7640 return Generators<T>(CATCH_MOVE(generator));
7641 }
7642 template<typename T, typename... Gs>
7643 auto makeGenerators( T&& val, Gs &&... moreGenerators ) -> Generators<std::decay_t<T>> {
7644 return makeGenerators( value( CATCH_FORWARD( val ) ), CATCH_FORWARD( moreGenerators )... );
7645 }
7646 template<typename T, typename U, typename... Gs>
7647 auto makeGenerators( as<T>, U&& val, Gs &&... moreGenerators ) -> Generators<T> {
7648 return makeGenerators( value( T( CATCH_FORWARD( val ) ) ), CATCH_FORWARD( moreGenerators )... );
7649 }
7650
7651 IGeneratorTracker* acquireGeneratorTracker( StringRef generatorName,
7652 SourceLineInfo const& lineInfo );
7653 IGeneratorTracker* createGeneratorTracker( StringRef generatorName,
7654 SourceLineInfo lineInfo,
7655 GeneratorBasePtr&& generator );
7656
7657 template<typename L>
7658 auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> typename decltype(generatorExpression())::type {
7659 using UnderlyingType = typename decltype(generatorExpression())::type;
7660
7661 IGeneratorTracker* tracker = acquireGeneratorTracker( generatorName, lineInfo );
7662 // Creation of tracker is delayed after generator creation, so
7663 // that constructing generator can fail without breaking everything.
7664 if (!tracker) {
7665 tracker = createGeneratorTracker(
7666 generatorName,
7667 lineInfo,
7668 Catch::Detail::make_unique<Generators<UnderlyingType>>(
7669 generatorExpression() ) );
7670 }
7671
7672 auto const& generator = static_cast<IGenerator<UnderlyingType> const&>( *tracker->getGenerator() );
7673 return generator.get();
7674 }
7675
7676} // namespace Generators
7677} // namespace Catch
7678
7679#define CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL( ... ) #__VA_ARGS__##_catch_sr
7680#define CATCH_INTERNAL_GENERATOR_STRINGIZE(...) CATCH_INTERNAL_GENERATOR_STRINGIZE_IMPL(__VA_ARGS__)
7681
7682#define GENERATE( ... ) \
7683 Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
7684 CATCH_INTERNAL_LINEINFO, \
7685 [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
7686#define GENERATE_COPY( ... ) \
7687 Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
7688 CATCH_INTERNAL_LINEINFO, \
7689 [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
7690#define GENERATE_REF( ... ) \
7691 Catch::Generators::generate( CATCH_INTERNAL_GENERATOR_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \
7692 CATCH_INTERNAL_LINEINFO, \
7693 [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace)
7694
7695#endif // CATCH_GENERATORS_HPP_INCLUDED
7696
7697
7698#ifndef CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
7699#define CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
7700
7701
7702#include <cassert>
7703
7704namespace Catch {
7705namespace Generators {
7706
7707 template <typename T>
7708 class TakeGenerator final : public IGenerator<T> {
7709 GeneratorWrapper<T> m_generator;
7710 size_t m_returned = 0;
7711 size_t m_target;
7712 public:
7713 TakeGenerator(size_t target, GeneratorWrapper<T>&& generator):
7714 m_generator(CATCH_MOVE(generator)),
7715 m_target(target)
7716 {
7717 assert(target != 0 && "Empty generators are not allowed");
7718 }
7719 T const& get() const override {
7720 return m_generator.get();
7721 }
7722 bool next() override {
7723 ++m_returned;
7724 if (m_returned >= m_target) {
7725 return false;
7726 }
7727
7728 const auto success = m_generator.next();
7729 // If the underlying generator does not contain enough values
7730 // then we cut short as well
7731 if (!success) {
7732 m_returned = m_target;
7733 }
7734 return success;
7735 }
7736 };
7737
7738 template <typename T>
7739 GeneratorWrapper<T> take(size_t target, GeneratorWrapper<T>&& generator) {
7740 return GeneratorWrapper<T>(Catch::Detail::make_unique<TakeGenerator<T>>(target, CATCH_MOVE(generator)));
7741 }
7742
7743
7744 template <typename T, typename Predicate>
7745 class FilterGenerator final : public IGenerator<T> {
7746 GeneratorWrapper<T> m_generator;
7747 Predicate m_predicate;
7748 public:
7749 template <typename P = Predicate>
7750 FilterGenerator(P&& pred, GeneratorWrapper<T>&& generator):
7751 m_generator(CATCH_MOVE(generator)),
7752 m_predicate(CATCH_FORWARD(pred))
7753 {
7754 if (!m_predicate(m_generator.get())) {
7755 // It might happen that there are no values that pass the
7756 // filter. In that case we throw an exception.
7757 auto has_initial_value = next();
7758 if (!has_initial_value) {
7759 Detail::throw_generator_exception("No valid value found in filtered generator");
7760 }
7761 }
7762 }
7763
7764 T const& get() const override {
7765 return m_generator.get();
7766 }
7767
7768 bool next() override {
7769 bool success = m_generator.next();
7770 if (!success) {
7771 return false;
7772 }
7773 while (!m_predicate(m_generator.get()) && (success = m_generator.next()) == true);
7774 return success;
7775 }
7776 };
7777
7778
7779 template <typename T, typename Predicate>
7780 GeneratorWrapper<T> filter(Predicate&& pred, GeneratorWrapper<T>&& generator) {
7781 return GeneratorWrapper<T>(Catch::Detail::make_unique<FilterGenerator<T, Predicate>>(CATCH_FORWARD(pred), CATCH_MOVE(generator)));
7782 }
7783
7784 template <typename T>
7785 class RepeatGenerator final : public IGenerator<T> {
7786 static_assert(!std::is_same<T, bool>::value,
7787 "RepeatGenerator currently does not support bools"
7788 "because of std::vector<bool> specialization");
7789 GeneratorWrapper<T> m_generator;
7790 mutable std::vector<T> m_returned;
7791 size_t m_target_repeats;
7792 size_t m_current_repeat = 0;
7793 size_t m_repeat_index = 0;
7794 public:
7795 RepeatGenerator(size_t repeats, GeneratorWrapper<T>&& generator):
7796 m_generator(CATCH_MOVE(generator)),
7797 m_target_repeats(repeats)
7798 {
7799 assert(m_target_repeats > 0 && "Repeat generator must repeat at least once");
7800 }
7801
7802 T const& get() const override {
7803 if (m_current_repeat == 0) {
7804 m_returned.push_back(m_generator.get());
7805 return m_returned.back();
7806 }
7807 return m_returned[m_repeat_index];
7808 }
7809
7810 bool next() override {
7811 // There are 2 basic cases:
7812 // 1) We are still reading the generator
7813 // 2) We are reading our own cache
7814
7815 // In the first case, we need to poke the underlying generator.
7816 // If it happily moves, we are left in that state, otherwise it is time to start reading from our cache
7817 if (m_current_repeat == 0) {
7818 const auto success = m_generator.next();
7819 if (!success) {
7820 ++m_current_repeat;
7821 }
7822 return m_current_repeat < m_target_repeats;
7823 }
7824
7825 // In the second case, we need to move indices forward and check that we haven't run up against the end
7826 ++m_repeat_index;
7827 if (m_repeat_index == m_returned.size()) {
7828 m_repeat_index = 0;
7829 ++m_current_repeat;
7830 }
7831 return m_current_repeat < m_target_repeats;
7832 }
7833 };
7834
7835 template <typename T>
7836 GeneratorWrapper<T> repeat(size_t repeats, GeneratorWrapper<T>&& generator) {
7837 return GeneratorWrapper<T>(Catch::Detail::make_unique<RepeatGenerator<T>>(repeats, CATCH_MOVE(generator)));
7838 }
7839
7840 template <typename T, typename U, typename Func>
7841 class MapGenerator final : public IGenerator<T> {
7842 // TBD: provide static assert for mapping function, for friendly error message
7843 GeneratorWrapper<U> m_generator;
7844 Func m_function;
7845 // To avoid returning dangling reference, we have to save the values
7846 T m_cache;
7847 public:
7848 template <typename F2 = Func>
7849 MapGenerator(F2&& function, GeneratorWrapper<U>&& generator) :
7850 m_generator(CATCH_MOVE(generator)),
7851 m_function(CATCH_FORWARD(function)),
7852 m_cache(m_function(m_generator.get()))
7853 {}
7854
7855 T const& get() const override {
7856 return m_cache;
7857 }
7858 bool next() override {
7859 const auto success = m_generator.next();
7860 if (success) {
7861 m_cache = m_function(m_generator.get());
7862 }
7863 return success;
7864 }
7865 };
7866
7867 template <typename Func, typename U, typename T = FunctionReturnType<Func, U>>
7868 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
7869 return GeneratorWrapper<T>(
7870 Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
7871 );
7872 }
7873
7874 template <typename T, typename U, typename Func>
7875 GeneratorWrapper<T> map(Func&& function, GeneratorWrapper<U>&& generator) {
7876 return GeneratorWrapper<T>(
7877 Catch::Detail::make_unique<MapGenerator<T, U, Func>>(CATCH_FORWARD(function), CATCH_MOVE(generator))
7878 );
7879 }
7880
7881 template <typename T>
7882 class ChunkGenerator final : public IGenerator<std::vector<T>> {
7883 std::vector<T> m_chunk;
7884 size_t m_chunk_size;
7885 GeneratorWrapper<T> m_generator;
7886 bool m_used_up = false;
7887 public:
7888 ChunkGenerator(size_t size, GeneratorWrapper<T> generator) :
7889 m_chunk_size(size), m_generator(CATCH_MOVE(generator))
7890 {
7891 m_chunk.reserve(m_chunk_size);
7892 if (m_chunk_size != 0) {
7893 m_chunk.push_back(m_generator.get());
7894 for (size_t i = 1; i < m_chunk_size; ++i) {
7895 if (!m_generator.next()) {
7896 Detail::throw_generator_exception("Not enough values to initialize the first chunk");
7897 }
7898 m_chunk.push_back(m_generator.get());
7899 }
7900 }
7901 }
7902 std::vector<T> const& get() const override {
7903 return m_chunk;
7904 }
7905 bool next() override {
7906 m_chunk.clear();
7907 for (size_t idx = 0; idx < m_chunk_size; ++idx) {
7908 if (!m_generator.next()) {
7909 return false;
7910 }
7911 m_chunk.push_back(m_generator.get());
7912 }
7913 return true;
7914 }
7915 };
7916
7917 template <typename T>
7918 GeneratorWrapper<std::vector<T>> chunk(size_t size, GeneratorWrapper<T>&& generator) {
7919 return GeneratorWrapper<std::vector<T>>(
7920 Catch::Detail::make_unique<ChunkGenerator<T>>(size, CATCH_MOVE(generator))
7921 );
7922 }
7923
7924} // namespace Generators
7925} // namespace Catch
7926
7927
7928#endif // CATCH_GENERATORS_ADAPTERS_HPP_INCLUDED
7929
7930
7931#ifndef CATCH_GENERATORS_RANDOM_HPP_INCLUDED
7932#define CATCH_GENERATORS_RANDOM_HPP_INCLUDED
7933
7934
7935
7936#ifndef CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
7937#define CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
7938
7939#include <cstdint>
7940
7941namespace Catch {
7942
7943 // This is a simple implementation of C++11 Uniform Random Number
7944 // Generator. It does not provide all operators, because Catch2
7945 // does not use it, but it should behave as expected inside stdlib's
7946 // distributions.
7947 // The implementation is based on the PCG family (http://pcg-random.org)
7948 class SimplePcg32 {
7949 using state_type = std::uint64_t;
7950 public:
7951 using result_type = std::uint32_t;
7952 static constexpr result_type (min)() {
7953 return 0;
7954 }
7955 static constexpr result_type (max)() {
7956 return static_cast<result_type>(-1);
7957 }
7958
7959 // Provide some default initial state for the default constructor
7960 SimplePcg32():SimplePcg32(0xed743cc4U) {}
7961
7962 explicit SimplePcg32(result_type seed_);
7963
7964 void seed(result_type seed_);
7965 void discard(uint64_t skip);
7966
7967 result_type operator()();
7968
7969 private:
7970 friend bool operator==(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
7971 friend bool operator!=(SimplePcg32 const& lhs, SimplePcg32 const& rhs);
7972
7973 // In theory we also need operator<< and operator>>
7974 // In practice we do not use them, so we will skip them for now
7975
7976
7977 std::uint64_t m_state;
7978 // This part of the state determines which "stream" of the numbers
7979 // is chosen -- we take it as a constant for Catch2, so we only
7980 // need to deal with seeding the main state.
7981 // Picked by reading 8 bytes from `/dev/random` :-)
7982 static const std::uint64_t s_inc = (0x13ed0cc53f939476ULL << 1ULL) | 1ULL;
7983 };
7984
7985} // end namespace Catch
7986
7987#endif // CATCH_RANDOM_NUMBER_GENERATOR_HPP_INCLUDED
7988
7989
7990
7991#ifndef CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
7992#define CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
7993
7994
7995
7996
7997#ifndef CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
7998#define CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
7999
8000#include <climits>
8001#include <cstddef>
8002#include <cstdint>
8003#include <type_traits>
8004
8005// Note: We use the usual enable-disable-autodetect dance here even though
8006// we do not support these in CMake configuration options (yet?).
8007// It is highly unlikely that we will need to make these actually
8008// user-configurable, but this will make it simpler if weend up needing
8009// it, and it provides an escape hatch to the users who need it.
8010#if defined( __SIZEOF_INT128__ )
8011# define CATCH_CONFIG_INTERNAL_UINT128
8012// Unlike GCC, MSVC does not polyfill umul as mulh + mul pair on ARM machines.
8013// Currently we do not bother doing this ourselves, but we could if it became
8014// important for perf.
8015#elif defined( _MSC_VER ) && defined( _M_X64 )
8016# define CATCH_CONFIG_INTERNAL_MSVC_UMUL128
8017#endif
8018
8019#if defined( CATCH_CONFIG_INTERNAL_UINT128 ) && \
8020 !defined( CATCH_CONFIG_NO_UINT128 ) && \
8021 !defined( CATCH_CONFIG_UINT128 )
8022#define CATCH_CONFIG_UINT128
8023#endif
8024
8025#if defined( CATCH_CONFIG_INTERNAL_MSVC_UMUL128 ) && \
8026 !defined( CATCH_CONFIG_NO_MSVC_UMUL128 ) && \
8027 !defined( CATCH_CONFIG_MSVC_UMUL128 )
8028# define CATCH_CONFIG_MSVC_UMUL128
8029# include <intrin.h>
8030#endif
8031
8032
8033namespace Catch {
8034 namespace Detail {
8035
8036 template <std::size_t>
8037 struct SizedUnsignedType;
8038#define SizedUnsignedTypeHelper( TYPE ) \
8039 template <> \
8040 struct SizedUnsignedType<sizeof( TYPE )> { \
8041 using type = TYPE; \
8042 }
8043
8044 SizedUnsignedTypeHelper( std::uint8_t );
8045 SizedUnsignedTypeHelper( std::uint16_t );
8046 SizedUnsignedTypeHelper( std::uint32_t );
8047 SizedUnsignedTypeHelper( std::uint64_t );
8048#undef SizedUnsignedTypeHelper
8049
8050 template <std::size_t sz>
8051 using SizedUnsignedType_t = typename SizedUnsignedType<sz>::type;
8052
8053 template <typename T>
8054 using DoubleWidthUnsignedType_t = SizedUnsignedType_t<2 * sizeof( T )>;
8055
8056 template <typename T>
8057 struct ExtendedMultResult {
8058 T upper;
8059 T lower;
8060 constexpr bool operator==( ExtendedMultResult const& rhs ) const {
8061 return upper == rhs.upper && lower == rhs.lower;
8062 }
8063 };
8064
8065 /**
8066 * Returns 128 bit result of lhs * rhs using portable C++ code
8067 *
8068 * This implementation is almost twice as fast as naive long multiplication,
8069 * and unlike intrinsic-based approach, it supports constexpr evaluation.
8070 */
8071 constexpr ExtendedMultResult<std::uint64_t>
8072 extendedMultPortable(std::uint64_t lhs, std::uint64_t rhs) {
8073#define CarryBits( x ) ( x >> 32 )
8074#define Digits( x ) ( x & 0xFF'FF'FF'FF )
8075 std::uint64_t lhs_low = Digits( lhs );
8076 std::uint64_t rhs_low = Digits( rhs );
8077 std::uint64_t low_low = ( lhs_low * rhs_low );
8078 std::uint64_t high_high = CarryBits( lhs ) * CarryBits( rhs );
8079
8080 // We add in carry bits from low-low already
8081 std::uint64_t high_low =
8082 ( CarryBits( lhs ) * rhs_low ) + CarryBits( low_low );
8083 // Note that we can add only low bits from high_low, to avoid
8084 // overflow with large inputs
8085 std::uint64_t low_high =
8086 ( lhs_low * CarryBits( rhs ) ) + Digits( high_low );
8087
8088 return { high_high + CarryBits( high_low ) + CarryBits( low_high ),
8089 ( low_high << 32 ) | Digits( low_low ) };
8090#undef CarryBits
8091#undef Digits
8092 }
8093
8094 //! Returns 128 bit result of lhs * rhs
8095 inline ExtendedMultResult<std::uint64_t>
8096 extendedMult( std::uint64_t lhs, std::uint64_t rhs ) {
8097#if defined( CATCH_CONFIG_UINT128 )
8098 auto result = __uint128_t( lhs ) * __uint128_t( rhs );
8099 return { static_cast<std::uint64_t>( result >> 64 ),
8100 static_cast<std::uint64_t>( result ) };
8101#elif defined( CATCH_CONFIG_MSVC_UMUL128 )
8102 std::uint64_t high;
8103 std::uint64_t low = _umul128( lhs, rhs, &high );
8104 return { high, low };
8105#else
8106 return extendedMultPortable( lhs, rhs );
8107#endif
8108 }
8109
8110
8111 template <typename UInt>
8112 constexpr ExtendedMultResult<UInt> extendedMult( UInt lhs, UInt rhs ) {
8113 static_assert( std::is_unsigned<UInt>::value,
8114 "extendedMult can only handle unsigned integers" );
8115 static_assert( sizeof( UInt ) < sizeof( std::uint64_t ),
8116 "Generic extendedMult can only handle types smaller "
8117 "than uint64_t" );
8118 using WideType = DoubleWidthUnsignedType_t<UInt>;
8119
8120 auto result = WideType( lhs ) * WideType( rhs );
8121 return {
8122 static_cast<UInt>( result >> ( CHAR_BIT * sizeof( UInt ) ) ),
8123 static_cast<UInt>( result & UInt( -1 ) ) };
8124 }
8125
8126
8127 template <typename TargetType,
8128 typename Generator>
8129 std::enable_if_t<sizeof(typename Generator::result_type) >= sizeof(TargetType),
8130 TargetType> fillBitsFrom(Generator& gen) {
8131 using gresult_type = typename Generator::result_type;
8132 static_assert( std::is_unsigned<TargetType>::value, "Only unsigned integers are supported" );
8133 static_assert( Generator::min() == 0 &&
8134 Generator::max() == static_cast<gresult_type>( -1 ),
8135 "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
8136
8137 // We want to return the top bits from a generator, as they are
8138 // usually considered higher quality.
8139 constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
8140 constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
8141
8142 return static_cast<TargetType>( gen() >>
8143 ( generated_bits - return_bits) );
8144 }
8145
8146 template <typename TargetType,
8147 typename Generator>
8148 std::enable_if_t<sizeof(typename Generator::result_type) < sizeof(TargetType),
8149 TargetType> fillBitsFrom(Generator& gen) {
8150 using gresult_type = typename Generator::result_type;
8151 static_assert( std::is_unsigned<TargetType>::value,
8152 "Only unsigned integers are supported" );
8153 static_assert( Generator::min() == 0 &&
8154 Generator::max() == static_cast<gresult_type>( -1 ),
8155 "Generator must be able to output all numbers in its result type (effectively it must be a random bit generator)" );
8156
8157 constexpr auto generated_bits = sizeof( gresult_type ) * CHAR_BIT;
8158 constexpr auto return_bits = sizeof( TargetType ) * CHAR_BIT;
8159 std::size_t filled_bits = 0;
8160 TargetType ret = 0;
8161 do {
8162 ret <<= generated_bits;
8163 ret |= gen();
8164 filled_bits += generated_bits;
8165 } while ( filled_bits < return_bits );
8166
8167 return ret;
8168 }
8169
8170 /*
8171 * Transposes numbers into unsigned type while keeping their ordering
8172 *
8173 * This means that signed types are changed so that the ordering is
8174 * [INT_MIN, ..., -1, 0, ..., INT_MAX], rather than order we would
8175 * get by simple casting ([0, ..., INT_MAX, INT_MIN, ..., -1])
8176 */
8177 template <typename OriginalType, typename UnsignedType>
8178 constexpr
8179 std::enable_if_t<std::is_signed<OriginalType>::value, UnsignedType>
8180 transposeToNaturalOrder( UnsignedType in ) {
8181 static_assert(
8182 sizeof( OriginalType ) == sizeof( UnsignedType ),
8183 "reordering requires the same sized types on both sides" );
8184 static_assert( std::is_unsigned<UnsignedType>::value,
8185 "Input type must be unsigned" );
8186 // Assuming 2s complement (standardized in current C++), the
8187 // positive and negative numbers are already internally ordered,
8188 // and their difference is in the top bit. Swapping it orders
8189 // them the desired way.
8190 constexpr auto highest_bit =
8191 UnsignedType( 1 ) << ( sizeof( UnsignedType ) * CHAR_BIT - 1 );
8192 return static_cast<UnsignedType>( in ^ highest_bit );
8193 }
8194
8195
8196
8197 template <typename OriginalType,
8198 typename UnsignedType>
8199 constexpr
8200 std::enable_if_t<std::is_unsigned<OriginalType>::value, UnsignedType>
8201 transposeToNaturalOrder(UnsignedType in) {
8202 static_assert(
8203 sizeof( OriginalType ) == sizeof( UnsignedType ),
8204 "reordering requires the same sized types on both sides" );
8205 static_assert( std::is_unsigned<UnsignedType>::value, "Input type must be unsigned" );
8206 // No reordering is needed for unsigned -> unsigned
8207 return in;
8208 }
8209 } // namespace Detail
8210} // namespace Catch
8211
8212#endif // CATCH_RANDOM_INTEGER_HELPERS_HPP_INCLUDED
8213
8214namespace Catch {
8215
8216/**
8217 * Implementation of uniform distribution on integers.
8218 *
8219 * Unlike `std::uniform_int_distribution`, this implementation supports
8220 * various 1 byte integral types, including bool (but you should not
8221 * actually use it for bools).
8222 *
8223 * The underlying algorithm is based on the one described in "Fast Random
8224 * Integer Generation in an Interval" by Daniel Lemire, but has been
8225 * optimized under the assumption of reuse of the same distribution object.
8226 */
8227template <typename IntegerType>
8228class uniform_integer_distribution {
8229 static_assert(std::is_integral<IntegerType>::value, "...");
8230
8231 using UnsignedIntegerType = Detail::SizedUnsignedType_t<sizeof(IntegerType)>;
8232
8233 // Only the left bound is stored, and we store it converted to its
8234 // unsigned image. This avoids having to do the conversions inside
8235 // the operator(), at the cost of having to do the conversion in
8236 // the a() getter. The right bound is only needed in the b() getter,
8237 // so we recompute it there from other stored data.
8238 UnsignedIntegerType m_a;
8239
8240 // How many different values are there in [a, b]. a == b => 1, can be 0 for distribution over all values in the type.
8241 UnsignedIntegerType m_ab_distance;
8242
8243 // We hoisted this out of the main generation function. Technically,
8244 // this means that using this distribution will be slower than Lemire's
8245 // algorithm if this distribution instance will be used only few times,
8246 // but it will be faster if it is used many times. Since Catch2 uses
8247 // distributions only to implement random generators, we assume that each
8248 // distribution will be reused many times and this is an optimization.
8249 UnsignedIntegerType m_rejection_threshold = 0;
8250
8251 static constexpr UnsignedIntegerType computeDistance(IntegerType a, IntegerType b) {
8252 // This overflows and returns 0 if a == 0 and b == TYPE_MAX.
8253 // We handle that later when generating the number.
8254 return transposeTo(b) - transposeTo(a) + 1;
8255 }
8256
8257 static constexpr UnsignedIntegerType computeRejectionThreshold(UnsignedIntegerType ab_distance) {
8258 // distance == 0 means that we will return all possible values from
8259 // the type's range, and that we shouldn't reject anything.
8260 if ( ab_distance == 0 ) { return 0; }
8261 return ( ~ab_distance + 1 ) % ab_distance;
8262 }
8263
8264 static constexpr UnsignedIntegerType transposeTo(IntegerType in) {
8265 return Detail::transposeToNaturalOrder<IntegerType>(
8266 static_cast<UnsignedIntegerType>( in ) );
8267 }
8268 static constexpr IntegerType transposeBack(UnsignedIntegerType in) {
8269 return static_cast<IntegerType>(
8270 Detail::transposeToNaturalOrder<IntegerType>(in) );
8271 }
8272
8273public:
8274 using result_type = IntegerType;
8275
8276 constexpr uniform_integer_distribution( IntegerType a, IntegerType b ):
8277 m_a( transposeTo(a) ),
8278 m_ab_distance( computeDistance(a, b) ),
8279 m_rejection_threshold( computeRejectionThreshold(m_ab_distance) ) {
8280 assert( a <= b );
8281 }
8282
8283 template <typename Generator>
8284 constexpr result_type operator()( Generator& g ) {
8285 // All possible values of result_type are valid.
8286 if ( m_ab_distance == 0 ) {
8287 return transposeBack( Detail::fillBitsFrom<UnsignedIntegerType>( g ) );
8288 }
8289
8290 auto random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
8291 auto emul = Detail::extendedMult( random_number, m_ab_distance );
8292 // Unlike Lemire's algorithm we skip the ab_distance check, since
8293 // we precomputed the rejection threshold, which is always tighter.
8294 while (emul.lower < m_rejection_threshold) {
8295 random_number = Detail::fillBitsFrom<UnsignedIntegerType>( g );
8296 emul = Detail::extendedMult( random_number, m_ab_distance );
8297 }
8298
8299 return transposeBack(m_a + emul.upper);
8300 }
8301
8302 constexpr result_type a() const { return transposeBack(m_a); }
8303 constexpr result_type b() const { return transposeBack(m_ab_distance + m_a - 1); }
8304};
8305
8306} // end namespace Catch
8307
8308#endif // CATCH_UNIFORM_INTEGER_DISTRIBUTION_HPP_INCLUDED
8309
8310
8311
8312#ifndef CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
8313#define CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
8314
8315
8316
8317
8318#ifndef CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
8319#define CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
8320
8321
8322
8323#ifndef CATCH_POLYFILLS_HPP_INCLUDED
8324#define CATCH_POLYFILLS_HPP_INCLUDED
8325
8326namespace Catch {
8327
8328 bool isnan(float f);
8329 bool isnan(double d);
8330
8331 float nextafter(float x, float y);
8332 double nextafter(double x, double y);
8333
8334}
8335
8336#endif // CATCH_POLYFILLS_HPP_INCLUDED
8337
8338#include <cassert>
8339#include <cmath>
8340#include <cstdint>
8341#include <limits>
8342#include <type_traits>
8343
8344namespace Catch {
8345
8346 namespace Detail {
8347 /**
8348 * Returns the largest magnitude of 1-ULP distance inside the [a, b] range.
8349 *
8350 * Assumes `a < b`.
8351 */
8352 template <typename FloatType>
8353 FloatType gamma(FloatType a, FloatType b) {
8354 static_assert( std::is_floating_point<FloatType>::value,
8355 "gamma returns the largest ULP magnitude within "
8356 "floating point range [a, b]. This only makes sense "
8357 "for floating point types" );
8358 assert( a <= b );
8359
8360 const auto gamma_up = Catch::nextafter( a, std::numeric_limits<FloatType>::infinity() ) - a;
8361 const auto gamma_down = b - Catch::nextafter( b, -std::numeric_limits<FloatType>::infinity() );
8362
8363 return gamma_up < gamma_down ? gamma_down : gamma_up;
8364 }
8365
8366 template <typename FloatingPoint>
8367 struct DistanceTypePicker;
8368 template <>
8369 struct DistanceTypePicker<float> {
8370 using type = std::uint32_t;
8371 };
8372 template <>
8373 struct DistanceTypePicker<double> {
8374 using type = std::uint64_t;
8375 };
8376
8377 template <typename T>
8378 using DistanceType = typename DistanceTypePicker<T>::type;
8379
8380#if defined( __GNUC__ ) || defined( __clang__ )
8381# pragma GCC diagnostic push
8382# pragma GCC diagnostic ignored "-Wfloat-equal"
8383#endif
8384 /**
8385 * Computes the number of equi-distant floats in [a, b]
8386 *
8387 * Since not every range can be split into equidistant floats
8388 * exactly, we actually compute ceil(b/distance - a/distance),
8389 * because in those cases we want to overcount.
8390 *
8391 * Uses modified Dekker's FastTwoSum algorithm to handle rounding.
8392 */
8393 template <typename FloatType>
8394 DistanceType<FloatType>
8395 count_equidistant_floats( FloatType a, FloatType b, FloatType distance ) {
8396 assert( a <= b );
8397 // We get distance as gamma for our uniform float distribution,
8398 // so this will round perfectly.
8399 const auto ag = a / distance;
8400 const auto bg = b / distance;
8401
8402 const auto s = bg - ag;
8403 const auto err = ( std::fabs( a ) <= std::fabs( b ) )
8404 ? -ag - ( s - bg )
8405 : bg - ( s + ag );
8406 const auto ceil_s = static_cast<DistanceType<FloatType>>( std::ceil( s ) );
8407
8408 return ( ceil_s != s ) ? ceil_s : ceil_s + ( err > 0 );
8409 }
8410#if defined( __GNUC__ ) || defined( __clang__ )
8411# pragma GCC diagnostic pop
8412#endif
8413
8414 }
8415
8416} // end namespace Catch
8417
8418#endif // CATCH_RANDOM_FLOATING_POINT_HELPERS_HPP_INCLUDED
8419
8420#include <cmath>
8421#include <type_traits>
8422
8423namespace Catch {
8424
8425 namespace Detail {
8426#if defined( __GNUC__ ) || defined( __clang__ )
8427# pragma GCC diagnostic push
8428# pragma GCC diagnostic ignored "-Wfloat-equal"
8429#endif
8430 // The issue with overflow only happens with maximal ULP and HUGE
8431 // distance, e.g. when generating numbers in [-inf, inf] for given
8432 // type. So we only check for the largest possible ULP in the
8433 // type, and return something that does not overflow to inf in 1 mult.
8434 constexpr std::uint64_t calculate_max_steps_in_one_go(double gamma) {
8435 if ( gamma == 1.99584030953472e+292 ) { return 9007199254740991; }
8436 return static_cast<std::uint64_t>( -1 );
8437 }
8438 constexpr std::uint32_t calculate_max_steps_in_one_go(float gamma) {
8439 if ( gamma == 2.028241e+31f ) { return 16777215; }
8440 return static_cast<std::uint32_t>( -1 );
8441 }
8442#if defined( __GNUC__ ) || defined( __clang__ )
8443# pragma GCC diagnostic pop
8444#endif
8445 }
8446
8447/**
8448 * Implementation of uniform distribution on floating point numbers.
8449 *
8450 * Note that we support only `float` and `double` types, because these
8451 * usually mean the same thing across different platform. `long double`
8452 * varies wildly by platform and thus we cannot provide reproducible
8453 * implementation. Also note that we don't implement all parts of
8454 * distribution per standard: this distribution is not serializable, nor
8455 * can the range be arbitrarily reset.
8456 *
8457 * The implementation also uses different approach than the one taken by
8458 * `std::uniform_real_distribution`, where instead of generating a number
8459 * between [0, 1) and then multiplying the range bounds with it, we first
8460 * split the [a, b] range into a set of equidistributed floating point
8461 * numbers, and then use uniform int distribution to pick which one to
8462 * return.
8463 *
8464 * This has the advantage of guaranteeing uniformity (the multiplication
8465 * method loses uniformity due to rounding when multiplying floats), except
8466 * for small non-uniformity at one side of the interval, where we have
8467 * to deal with the fact that not every interval is splittable into
8468 * equidistributed floats.
8469 *
8470 * Based on "Drawing random floating-point numbers from an interval" by
8471 * Frederic Goualard.
8472 */
8473template <typename FloatType>
8474class uniform_floating_point_distribution {
8475 static_assert(std::is_floating_point<FloatType>::value, "...");
8476 static_assert(!std::is_same<FloatType, long double>::value,
8477 "We do not support long double due to inconsistent behaviour between platforms");
8478
8479 using WidthType = Detail::DistanceType<FloatType>;
8480
8481 FloatType m_a, m_b;
8482 FloatType m_ulp_magnitude;
8483 WidthType m_floats_in_range;
8484 uniform_integer_distribution<WidthType> m_int_dist;
8485
8486 // In specific cases, we can overflow into `inf` when computing the
8487 // `steps * g` offset. To avoid this, we don't offset by more than this
8488 // in one multiply + addition.
8489 WidthType m_max_steps_in_one_go;
8490 // We don't want to do the magnitude check every call to `operator()`
8491 bool m_a_has_leq_magnitude;
8492
8493public:
8494 using result_type = FloatType;
8495
8496 uniform_floating_point_distribution( FloatType a, FloatType b ):
8497 m_a( a ),
8498 m_b( b ),
8499 m_ulp_magnitude( Detail::gamma( m_a, m_b ) ),
8500 m_floats_in_range( Detail::count_equidistant_floats( m_a, m_b, m_ulp_magnitude ) ),
8501 m_int_dist(0, m_floats_in_range),
8502 m_max_steps_in_one_go( Detail::calculate_max_steps_in_one_go(m_ulp_magnitude)),
8503 m_a_has_leq_magnitude(std::fabs(m_a) <= std::fabs(m_b))
8504 {
8505 assert( a <= b );
8506 }
8507
8508 template <typename Generator>
8509 result_type operator()( Generator& g ) {
8510 WidthType steps = m_int_dist( g );
8511 if ( m_a_has_leq_magnitude ) {
8512 if ( steps == m_floats_in_range ) { return m_a; }
8513 auto b = m_b;
8514 while (steps > m_max_steps_in_one_go) {
8515 b -= m_max_steps_in_one_go * m_ulp_magnitude;
8516 steps -= m_max_steps_in_one_go;
8517 }
8518 return b - steps * m_ulp_magnitude;
8519 } else {
8520 if ( steps == m_floats_in_range ) { return m_b; }
8521 auto a = m_a;
8522 while (steps > m_max_steps_in_one_go) {
8523 a += m_max_steps_in_one_go * m_ulp_magnitude;
8524 steps -= m_max_steps_in_one_go;
8525 }
8526 return a + steps * m_ulp_magnitude;
8527 }
8528 }
8529
8530 result_type a() const { return m_a; }
8531 result_type b() const { return m_b; }
8532};
8533
8534} // end namespace Catch
8535
8536#endif // CATCH_UNIFORM_FLOATING_POINT_DISTRIBUTION_HPP_INCLUDED
8537
8538namespace Catch {
8539namespace Generators {
8540namespace Detail {
8541 // Returns a suitable seed for a random floating generator based off
8542 // the primary internal rng. It does so by taking current value from
8543 // the rng and returning it as the seed.
8544 std::uint32_t getSeed();
8545}
8546
8547template <typename Float>
8548class RandomFloatingGenerator final : public IGenerator<Float> {
8549 Catch::SimplePcg32 m_rng;
8550 Catch::uniform_floating_point_distribution<Float> m_dist;
8551 Float m_current_number;
8552public:
8553 RandomFloatingGenerator( Float a, Float b, std::uint32_t seed ):
8554 m_rng(seed),
8555 m_dist(a, b) {
8556 static_cast<void>(next());
8557 }
8558
8559 Float const& get() const override {
8560 return m_current_number;
8561 }
8562 bool next() override {
8563 m_current_number = m_dist(m_rng);
8564 return true;
8565 }
8566};
8567
8568template <>
8569class RandomFloatingGenerator<long double> final : public IGenerator<long double> {
8570 // We still rely on <random> for this specialization, but we don't
8571 // want to drag it into the header.
8572 struct PImpl;
8573 Catch::Detail::unique_ptr<PImpl> m_pimpl;
8574 long double m_current_number;
8575
8576public:
8577 RandomFloatingGenerator( long double a, long double b, std::uint32_t seed );
8578
8579 long double const& get() const override { return m_current_number; }
8580 bool next() override;
8581
8582 ~RandomFloatingGenerator() override; // = default
8583};
8584
8585template <typename Integer>
8586class RandomIntegerGenerator final : public IGenerator<Integer> {
8587 Catch::SimplePcg32 m_rng;
8588 Catch::uniform_integer_distribution<Integer> m_dist;
8589 Integer m_current_number;
8590public:
8591 RandomIntegerGenerator( Integer a, Integer b, std::uint32_t seed ):
8592 m_rng(seed),
8593 m_dist(a, b) {
8594 static_cast<void>(next());
8595 }
8596
8597 Integer const& get() const override {
8598 return m_current_number;
8599 }
8600 bool next() override {
8601 m_current_number = m_dist(m_rng);
8602 return true;
8603 }
8604};
8605
8606template <typename T>
8607std::enable_if_t<std::is_integral<T>::value, GeneratorWrapper<T>>
8608random(T a, T b) {
8609 return GeneratorWrapper<T>(
8610 Catch::Detail::make_unique<RandomIntegerGenerator<T>>(a, b, Detail::getSeed())
8611 );
8612}
8613
8614template <typename T>
8615std::enable_if_t<std::is_floating_point<T>::value,
8616GeneratorWrapper<T>>
8617random(T a, T b) {
8618 return GeneratorWrapper<T>(
8619 Catch::Detail::make_unique<RandomFloatingGenerator<T>>(a, b, Detail::getSeed())
8620 );
8621}
8622
8623
8624} // namespace Generators
8625} // namespace Catch
8626
8627
8628#endif // CATCH_GENERATORS_RANDOM_HPP_INCLUDED
8629
8630
8631#ifndef CATCH_GENERATORS_RANGE_HPP_INCLUDED
8632#define CATCH_GENERATORS_RANGE_HPP_INCLUDED
8633
8634
8635#include <iterator>
8636#include <type_traits>
8637
8638namespace Catch {
8639namespace Generators {
8640
8641
8642template <typename T>
8643class RangeGenerator final : public IGenerator<T> {
8644 T m_current;
8645 T m_end;
8646 T m_step;
8647 bool m_positive;
8648
8649public:
8650 RangeGenerator(T const& start, T const& end, T const& step):
8651 m_current(start),
8652 m_end(end),
8653 m_step(step),
8654 m_positive(m_step > T(0))
8655 {
8656 assert(m_current != m_end && "Range start and end cannot be equal");
8657 assert(m_step != T(0) && "Step size cannot be zero");
8658 assert(((m_positive && m_current <= m_end) || (!m_positive && m_current >= m_end)) && "Step moves away from end");
8659 }
8660
8661 RangeGenerator(T const& start, T const& end):
8662 RangeGenerator(start, end, (start < end) ? T(1) : T(-1))
8663 {}
8664
8665 T const& get() const override {
8666 return m_current;
8667 }
8668
8669 bool next() override {
8670 m_current += m_step;
8671 return (m_positive) ? (m_current < m_end) : (m_current > m_end);
8672 }
8673};
8674
8675template <typename T>
8676GeneratorWrapper<T> range(T const& start, T const& end, T const& step) {
8677 static_assert(std::is_arithmetic<T>::value && !std::is_same<T, bool>::value, "Type must be numeric");
8678 return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end, step));
8679}
8680
8681template <typename T>
8682GeneratorWrapper<T> range(T const& start, T const& end) {
8683 static_assert(std::is_integral<T>::value && !std::is_same<T, bool>::value, "Type must be an integer");
8684 return GeneratorWrapper<T>(Catch::Detail::make_unique<RangeGenerator<T>>(start, end));
8685}
8686
8687
8688template <typename T>
8689class IteratorGenerator final : public IGenerator<T> {
8690 static_assert(!std::is_same<T, bool>::value,
8691 "IteratorGenerator currently does not support bools"
8692 "because of std::vector<bool> specialization");
8693
8694 std::vector<T> m_elems;
8695 size_t m_current = 0;
8696public:
8697 template <typename InputIterator, typename InputSentinel>
8698 IteratorGenerator(InputIterator first, InputSentinel last):m_elems(first, last) {
8699 if (m_elems.empty()) {
8700 Detail::throw_generator_exception("IteratorGenerator received no valid values");
8701 }
8702 }
8703
8704 T const& get() const override {
8705 return m_elems[m_current];
8706 }
8707
8708 bool next() override {
8709 ++m_current;
8710 return m_current != m_elems.size();
8711 }
8712};
8713
8714template <typename InputIterator,
8715 typename InputSentinel,
8716 typename ResultType = typename std::iterator_traits<InputIterator>::value_type>
8717GeneratorWrapper<ResultType> from_range(InputIterator from, InputSentinel to) {
8718 return GeneratorWrapper<ResultType>(Catch::Detail::make_unique<IteratorGenerator<ResultType>>(from, to));
8719}
8720
8721template <typename Container>
8722auto from_range(Container const& cnt) {
8723 using std::begin;
8724 using std::end;
8725 return from_range( begin( cnt ), end( cnt ) );
8726}
8727
8728
8729} // namespace Generators
8730} // namespace Catch
8731
8732
8733#endif // CATCH_GENERATORS_RANGE_HPP_INCLUDED
8734
8735#endif // CATCH_GENERATORS_ALL_HPP_INCLUDED
8736
8737
8738/** \file
8739 * This is a convenience header for Catch2's interfaces. It includes
8740 * **all** of Catch2 headers related to interfaces.
8741 *
8742 * Generally the Catch2 users should use specific includes they need,
8743 * but this header can be used instead for ease-of-experimentation, or
8744 * just plain convenience, at the cost of somewhat increased compilation
8745 * times.
8746 *
8747 * When a new header is added to either the `interfaces` folder, or to
8748 * the corresponding internal subfolder, it should be added here.
8749 */
8750
8751
8752#ifndef CATCH_INTERFACES_ALL_HPP_INCLUDED
8753#define CATCH_INTERFACES_ALL_HPP_INCLUDED
8754
8755
8756
8757#ifndef CATCH_INTERFACES_REPORTER_HPP_INCLUDED
8758#define CATCH_INTERFACES_REPORTER_HPP_INCLUDED
8759
8760
8761
8762#ifndef CATCH_TEST_RUN_INFO_HPP_INCLUDED
8763#define CATCH_TEST_RUN_INFO_HPP_INCLUDED
8764
8765
8766namespace Catch {
8767
8768 struct TestRunInfo {
8769 constexpr TestRunInfo(StringRef _name) : name(_name) {}
8770 StringRef name;
8771 };
8772
8773} // end namespace Catch
8774
8775#endif // CATCH_TEST_RUN_INFO_HPP_INCLUDED
8776
8777#include <map>
8778#include <string>
8779#include <vector>
8780#include <iosfwd>
8781
8782namespace Catch {
8783
8784 struct ReporterDescription;
8785 struct ListenerDescription;
8786 struct TagInfo;
8787 struct TestCaseInfo;
8788 class TestCaseHandle;
8789 class IConfig;
8790 class IStream;
8791 enum class ColourMode : std::uint8_t;
8792
8793 struct ReporterConfig {
8794 ReporterConfig( IConfig const* _fullConfig,
8795 Detail::unique_ptr<IStream> _stream,
8796 ColourMode colourMode,
8797 std::map<std::string, std::string> customOptions );
8798
8799 ReporterConfig( ReporterConfig&& ) = default;
8800 ReporterConfig& operator=( ReporterConfig&& ) = default;
8801 ~ReporterConfig(); // = default
8802
8803 Detail::unique_ptr<IStream> takeStream() &&;
8804 IConfig const* fullConfig() const;
8805 ColourMode colourMode() const;
8806 std::map<std::string, std::string> const& customOptions() const;
8807
8808 private:
8809 Detail::unique_ptr<IStream> m_stream;
8810 IConfig const* m_fullConfig;
8811 ColourMode m_colourMode;
8812 std::map<std::string, std::string> m_customOptions;
8813 };
8814
8815 struct AssertionStats {
8816 AssertionStats( AssertionResult const& _assertionResult,
8817 std::vector<MessageInfo> const& _infoMessages,
8818 Totals const& _totals );
8819
8820 AssertionStats( AssertionStats const& ) = default;
8821 AssertionStats( AssertionStats && ) = default;
8822 AssertionStats& operator = ( AssertionStats const& ) = delete;
8823 AssertionStats& operator = ( AssertionStats && ) = delete;
8824
8825 AssertionResult assertionResult;
8826 std::vector<MessageInfo> infoMessages;
8827 Totals totals;
8828 };
8829
8830 struct SectionStats {
8831 SectionStats( SectionInfo&& _sectionInfo,
8832 Counts const& _assertions,
8833 double _durationInSeconds,
8834 bool _missingAssertions );
8835
8836 SectionInfo sectionInfo;
8837 Counts assertions;
8838 double durationInSeconds;
8839 bool missingAssertions;
8840 };
8841
8842 struct TestCaseStats {
8843 TestCaseStats( TestCaseInfo const& _testInfo,
8844 Totals const& _totals,
8845 std::string&& _stdOut,
8846 std::string&& _stdErr,
8847 bool _aborting );
8848
8849 TestCaseInfo const * testInfo;
8850 Totals totals;
8851 std::string stdOut;
8852 std::string stdErr;
8853 bool aborting;
8854 };
8855
8856 struct TestRunStats {
8857 TestRunStats( TestRunInfo const& _runInfo,
8858 Totals const& _totals,
8859 bool _aborting );
8860
8861 TestRunInfo runInfo;
8862 Totals totals;
8863 bool aborting;
8864 };
8865
8866 //! By setting up its preferences, a reporter can modify Catch2's behaviour
8867 //! in some regards, e.g. it can request Catch2 to capture writes to
8868 //! stdout/stderr during test execution, and pass them to the reporter.
8869 struct ReporterPreferences {
8870 //! Catch2 should redirect writes to stdout and pass them to the
8871 //! reporter
8872 bool shouldRedirectStdOut = false;
8873 //! Catch2 should call `Reporter::assertionEnded` even for passing
8874 //! assertions
8875 bool shouldReportAllAssertions = false;
8876 };
8877
8878 /**
8879 * The common base for all reporters and event listeners
8880 *
8881 * Implementing classes must also implement:
8882 *
8883 * //! User-friendly description of the reporter/listener type
8884 * static std::string getDescription()
8885 *
8886 * Generally shouldn't be derived from by users of Catch2 directly,
8887 * instead they should derive from one of the utility bases that
8888 * derive from this class.
8889 */
8890 class IEventListener {
8891 protected:
8892 //! Derived classes can set up their preferences here
8893 ReporterPreferences m_preferences;
8894 //! The test run's config as filled in from CLI and defaults
8895 IConfig const* m_config;
8896
8897 public:
8898 IEventListener( IConfig const* config ): m_config( config ) {}
8899
8900 virtual ~IEventListener(); // = default;
8901
8902 // Implementing class must also provide the following static methods:
8903 // static std::string getDescription();
8904
8905 ReporterPreferences const& getPreferences() const {
8906 return m_preferences;
8907 }
8908
8909 //! Called when no test cases match provided test spec
8910 virtual void noMatchingTestCases( StringRef unmatchedSpec ) = 0;
8911 //! Called for all invalid test specs from the cli
8912 virtual void reportInvalidTestSpec( StringRef invalidArgument ) = 0;
8913
8914 /**
8915 * Called once in a testing run before tests are started
8916 *
8917 * Not called if tests won't be run (e.g. only listing will happen)
8918 */
8919 virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
8920
8921 //! Called _once_ for each TEST_CASE, no matter how many times it is entered
8922 virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
8923 //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
8924 virtual void testCasePartialStarting( TestCaseInfo const& testInfo, uint64_t partNumber ) = 0;
8925 //! Called when a `SECTION` is being entered. Not called for skipped sections
8926 virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
8927
8928 //! Called when user-code is being probed before the actual benchmark runs
8929 virtual void benchmarkPreparing( StringRef benchmarkName ) = 0;
8930 //! Called after probe but before the user-code is being benchmarked
8931 virtual void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) = 0;
8932 //! Called with the benchmark results if benchmark successfully finishes
8933 virtual void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) = 0;
8934 //! Called if running the benchmarks fails for any reason
8935 virtual void benchmarkFailed( StringRef benchmarkName ) = 0;
8936
8937 //! Called before assertion success/failure is evaluated
8938 virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
8939
8940 //! Called after assertion was fully evaluated
8941 virtual void assertionEnded( AssertionStats const& assertionStats ) = 0;
8942
8943 //! Called after a `SECTION` has finished running
8944 virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
8945 //! Called _every time_ a TEST_CASE is entered, including repeats (due to sections)
8946 virtual void testCasePartialEnded(TestCaseStats const& testCaseStats, uint64_t partNumber ) = 0;
8947 //! Called _once_ for each TEST_CASE, no matter how many times it is entered
8948 virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
8949 /**
8950 * Called once after all tests in a testing run are finished
8951 *
8952 * Not called if tests weren't run (e.g. only listings happened)
8953 */
8954 virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
8955
8956 /**
8957 * Called with test cases that are skipped due to the test run aborting.
8958 * NOT called for test cases that are explicitly skipped using the `SKIP` macro.
8959 *
8960 * Deprecated - will be removed in the next major release.
8961 */
8962 virtual void skipTest( TestCaseInfo const& testInfo ) = 0;
8963
8964 //! Called if a fatal error (signal/structured exception) occurred
8965 virtual void fatalErrorEncountered( StringRef error ) = 0;
8966
8967 //! Writes out information about provided reporters using reporter-specific format
8968 virtual void listReporters(std::vector<ReporterDescription> const& descriptions) = 0;
8969 //! Writes out the provided listeners descriptions using reporter-specific format
8970 virtual void listListeners(std::vector<ListenerDescription> const& descriptions) = 0;
8971 //! Writes out information about provided tests using reporter-specific format
8972 virtual void listTests(std::vector<TestCaseHandle> const& tests) = 0;
8973 //! Writes out information about the provided tags using reporter-specific format
8974 virtual void listTags(std::vector<TagInfo> const& tags) = 0;
8975 };
8976 using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
8977
8978} // end namespace Catch
8979
8980#endif // CATCH_INTERFACES_REPORTER_HPP_INCLUDED
8981
8982
8983#ifndef CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
8984#define CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
8985
8986
8987#include <string>
8988
8989namespace Catch {
8990
8991 struct ReporterConfig;
8992 class IConfig;
8993 class IEventListener;
8994 using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
8995
8996
8997 class IReporterFactory {
8998 public:
8999 virtual ~IReporterFactory(); // = default
9000
9001 virtual IEventListenerPtr
9002 create( ReporterConfig&& config ) const = 0;
9003 virtual std::string getDescription() const = 0;
9004 };
9005 using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
9006
9007 class EventListenerFactory {
9008 public:
9009 virtual ~EventListenerFactory(); // = default
9010 virtual IEventListenerPtr create( IConfig const* config ) const = 0;
9011 //! Return a meaningful name for the listener, e.g. its type name
9012 virtual StringRef getName() const = 0;
9013 //! Return listener's description if available
9014 virtual std::string getDescription() const = 0;
9015 };
9016} // namespace Catch
9017
9018#endif // CATCH_INTERFACES_REPORTER_FACTORY_HPP_INCLUDED
9019
9020
9021#ifndef CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
9022#define CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
9023
9024#include <string>
9025
9026namespace Catch {
9027
9028 struct TagAlias;
9029
9030 class ITagAliasRegistry {
9031 public:
9032 virtual ~ITagAliasRegistry(); // = default
9033 // Nullptr if not present
9034 virtual TagAlias const* find( std::string const& alias ) const = 0;
9035 virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
9036
9037 static ITagAliasRegistry const& get();
9038 };
9039
9040} // end namespace Catch
9041
9042#endif // CATCH_INTERFACES_TAG_ALIAS_REGISTRY_HPP_INCLUDED
9043
9044
9045#ifndef CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
9046#define CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
9047
9048#include <vector>
9049
9050namespace Catch {
9051
9052 struct TestCaseInfo;
9053 class TestCaseHandle;
9054 class IConfig;
9055
9056 class ITestCaseRegistry {
9057 public:
9058 virtual ~ITestCaseRegistry(); // = default
9059 // TODO: this exists only for adding filenames to test cases -- let's expose this in a saner way later
9060 virtual std::vector<TestCaseInfo* > const& getAllInfos() const = 0;
9061 virtual std::vector<TestCaseHandle> const& getAllTests() const = 0;
9062 virtual std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const = 0;
9063 };
9064
9065}
9066
9067#endif // CATCH_INTERFACES_TESTCASE_HPP_INCLUDED
9068
9069#endif // CATCH_INTERFACES_ALL_HPP_INCLUDED
9070
9071
9072#ifndef CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
9073#define CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
9074
9075
9076namespace Catch {
9077 namespace Detail {
9078 //! Provides case-insensitive `op<` semantics when called
9079 struct CaseInsensitiveLess {
9080 bool operator()( StringRef lhs,
9081 StringRef rhs ) const;
9082 };
9083
9084 //! Provides case-insensitive `op==` semantics when called
9085 struct CaseInsensitiveEqualTo {
9086 bool operator()( StringRef lhs,
9087 StringRef rhs ) const;
9088 };
9089
9090 } // namespace Detail
9091} // namespace Catch
9092
9093#endif // CATCH_CASE_INSENSITIVE_COMPARISONS_HPP_INCLUDED
9094
9095
9096
9097/** \file
9098 * Wrapper for ANDROID_LOGWRITE configuration option
9099 *
9100 * We want to default to enabling it when compiled for android, but
9101 * users of the library should also be able to disable it if they want
9102 * to.
9103 */
9104
9105#ifndef CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
9106#define CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
9107
9108
9109#if defined(__ANDROID__)
9110# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE
9111#endif
9112
9113
9114#if defined( CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE ) && \
9115 !defined( CATCH_CONFIG_NO_ANDROID_LOGWRITE ) && \
9116 !defined( CATCH_CONFIG_ANDROID_LOGWRITE )
9117# define CATCH_CONFIG_ANDROID_LOGWRITE
9118#endif
9119
9120#endif // CATCH_CONFIG_ANDROID_LOGWRITE_HPP_INCLUDED
9121
9122
9123
9124/** \file
9125 * Wrapper for UNCAUGHT_EXCEPTIONS configuration option
9126 *
9127 * For some functionality, Catch2 requires to know whether there is
9128 * an active exception. Because `std::uncaught_exception` is deprecated
9129 * in C++17, we want to use `std::uncaught_exceptions` if possible.
9130 */
9131
9132#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
9133#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
9134
9135
9136#if defined(_MSC_VER)
9137# if _MSC_VER >= 1900 // Visual Studio 2015 or newer
9138# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
9139# endif
9140#endif
9141
9142
9143#include <exception>
9144
9145#if defined(__cpp_lib_uncaught_exceptions) \
9146 && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
9147
9148# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
9149#endif // __cpp_lib_uncaught_exceptions
9150
9151
9152#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \
9153 && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \
9154 && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS)
9155
9156# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS
9157#endif
9158
9159
9160#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
9161
9162
9163#ifndef CATCH_CONSOLE_COLOUR_HPP_INCLUDED
9164#define CATCH_CONSOLE_COLOUR_HPP_INCLUDED
9165
9166
9167#include <iosfwd>
9168#include <cstdint>
9169
9170namespace Catch {
9171
9172 enum class ColourMode : std::uint8_t;
9173 class IStream;
9174
9175 struct Colour {
9176 enum Code {
9177 None = 0,
9178
9179 White,
9180 Red,
9181 Green,
9182 Blue,
9183 Cyan,
9184 Yellow,
9185 Grey,
9186
9187 Bright = 0x10,
9188
9189 BrightRed = Bright | Red,
9190 BrightGreen = Bright | Green,
9191 LightGrey = Bright | Grey,
9192 BrightWhite = Bright | White,
9193 BrightYellow = Bright | Yellow,
9194
9195 // By intention
9196 FileName = LightGrey,
9197 Warning = BrightYellow,
9198 ResultError = BrightRed,
9199 ResultSuccess = BrightGreen,
9200 ResultExpectedFailure = Warning,
9201
9202 Error = BrightRed,
9203 Success = Green,
9204 Skip = LightGrey,
9205
9206 OriginalExpression = Cyan,
9207 ReconstructedExpression = BrightYellow,
9208
9209 SecondaryText = LightGrey,
9210 Headers = White
9211 };
9212 };
9213
9214 class ColourImpl {
9215 protected:
9216 //! The associated stream of this ColourImpl instance
9217 IStream* m_stream;
9218 public:
9219 ColourImpl( IStream* stream ): m_stream( stream ) {}
9220
9221 //! RAII wrapper around writing specific colour of text using specific
9222 //! colour impl into a stream.
9223 class ColourGuard {
9224 ColourImpl const* m_colourImpl;
9225 Colour::Code m_code;
9226 bool m_engaged = false;
9227
9228 public:
9229 //! Does **not** engage the guard/start the colour
9230 ColourGuard( Colour::Code code,
9231 ColourImpl const* colour );
9232
9233 ColourGuard( ColourGuard const& rhs ) = delete;
9234 ColourGuard& operator=( ColourGuard const& rhs ) = delete;
9235
9236 ColourGuard( ColourGuard&& rhs ) noexcept;
9237 ColourGuard& operator=( ColourGuard&& rhs ) noexcept;
9238
9239 //! Removes colour _if_ the guard was engaged
9240 ~ColourGuard();
9241
9242 /**
9243 * Explicitly engages colour for given stream.
9244 *
9245 * The API based on operator<< should be preferred.
9246 */
9247 ColourGuard& engage( std::ostream& stream ) &;
9248 /**
9249 * Explicitly engages colour for given stream.
9250 *
9251 * The API based on operator<< should be preferred.
9252 */
9253 ColourGuard&& engage( std::ostream& stream ) &&;
9254
9255 private:
9256 //! Engages the guard and starts using colour
9257 friend std::ostream& operator<<( std::ostream& lhs,
9258 ColourGuard& guard ) {
9259 guard.engageImpl( lhs );
9260 return lhs;
9261 }
9262 //! Engages the guard and starts using colour
9263 friend std::ostream& operator<<( std::ostream& lhs,
9264 ColourGuard&& guard) {
9265 guard.engageImpl( lhs );
9266 return lhs;
9267 }
9268
9269 void engageImpl( std::ostream& stream );
9270
9271 };
9272
9273 virtual ~ColourImpl(); // = default
9274 /**
9275 * Creates a guard object for given colour and this colour impl
9276 *
9277 * **Important:**
9278 * the guard starts disengaged, and has to be engaged explicitly.
9279 */
9280 ColourGuard guardColour( Colour::Code colourCode );
9281
9282 private:
9283 virtual void use( Colour::Code colourCode ) const = 0;
9284 };
9285
9286 //! Provides ColourImpl based on global config and target compilation platform
9287 Detail::unique_ptr<ColourImpl> makeColourImpl( ColourMode colourSelection,
9288 IStream* stream );
9289
9290 //! Checks if specific colour impl has been compiled into the binary
9291 bool isColourImplAvailable( ColourMode colourSelection );
9292
9293} // end namespace Catch
9294
9295#endif // CATCH_CONSOLE_COLOUR_HPP_INCLUDED
9296
9297
9298#ifndef CATCH_CONSOLE_WIDTH_HPP_INCLUDED
9299#define CATCH_CONSOLE_WIDTH_HPP_INCLUDED
9300
9301// This include must be kept so that user's configured value for CONSOLE_WIDTH
9302// is used before we attempt to provide a default value
9303
9304#ifndef CATCH_CONFIG_CONSOLE_WIDTH
9305#define CATCH_CONFIG_CONSOLE_WIDTH 80
9306#endif
9307
9308#endif // CATCH_CONSOLE_WIDTH_HPP_INCLUDED
9309
9310
9311#ifndef CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
9312#define CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
9313
9314
9315#include <cstddef>
9316#include <initializer_list>
9317
9318// We want a simple polyfill over `std::empty`, `std::size` and so on
9319// for C++14 or C++ libraries with incomplete support.
9320// We also have to handle that MSVC std lib will happily provide these
9321// under older standards.
9322#if defined(CATCH_CPP17_OR_GREATER) || defined(_MSC_VER)
9323
9324// We are already using this header either way, so there shouldn't
9325// be much additional overhead in including it to get the feature
9326// test macros
9327#include <string>
9328
9329# if !defined(__cpp_lib_nonmember_container_access)
9330# define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
9331# endif
9332
9333#else
9334#define CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
9335#endif
9336
9337
9338
9339namespace Catch {
9340namespace Detail {
9341
9342#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
9343 template <typename Container>
9344 constexpr auto empty(Container const& cont) -> decltype(cont.empty()) {
9345 return cont.empty();
9346 }
9347 template <typename T, std::size_t N>
9348 constexpr bool empty(const T (&)[N]) noexcept {
9349 // GCC < 7 does not support the const T(&)[] parameter syntax
9350 // so we have to ignore the length explicitly
9351 (void)N;
9352 return false;
9353 }
9354 template <typename T>
9355 constexpr bool empty(std::initializer_list<T> list) noexcept {
9356 return list.size() > 0;
9357 }
9358
9359
9360 template <typename Container>
9361 constexpr auto size(Container const& cont) -> decltype(cont.size()) {
9362 return cont.size();
9363 }
9364 template <typename T, std::size_t N>
9365 constexpr std::size_t size(const T(&)[N]) noexcept {
9366 return N;
9367 }
9368#endif // CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS
9369
9370} // end namespace Detail
9371} // end namespace Catch
9372
9373
9374
9375#endif // CATCH_CONTAINER_NONMEMBERS_HPP_INCLUDED
9376
9377
9378#ifndef CATCH_DEBUG_CONSOLE_HPP_INCLUDED
9379#define CATCH_DEBUG_CONSOLE_HPP_INCLUDED
9380
9381#include <string>
9382
9383namespace Catch {
9384 void writeToDebugConsole( std::string const& text );
9385}
9386
9387#endif // CATCH_DEBUG_CONSOLE_HPP_INCLUDED
9388
9389
9390#ifndef CATCH_DEBUGGER_HPP_INCLUDED
9391#define CATCH_DEBUGGER_HPP_INCLUDED
9392
9393
9394namespace Catch {
9395 bool isDebuggerActive();
9396}
9397
9398#ifdef CATCH_PLATFORM_MAC
9399
9400 #if defined(__i386__) || defined(__x86_64__)
9401 #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */
9402 #elif defined(__aarch64__)
9403 #define CATCH_TRAP() __asm__(".inst 0xd43e0000")
9404 #elif defined(__POWERPC__)
9405 #define CATCH_TRAP() __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
9406 : : : "memory","r0","r3","r4" ) /* NOLINT */
9407 #endif
9408
9409#elif defined(CATCH_PLATFORM_IPHONE)
9410
9411 // use inline assembler
9412 #if defined(__i386__) || defined(__x86_64__)
9413 #define CATCH_TRAP() __asm__("int $3")
9414 #elif defined(__aarch64__)
9415 #define CATCH_TRAP() __asm__(".inst 0xd4200000")
9416 #elif defined(__arm__) && !defined(__thumb__)
9417 #define CATCH_TRAP() __asm__(".inst 0xe7f001f0")
9418 #elif defined(__arm__) && defined(__thumb__)
9419 #define CATCH_TRAP() __asm__(".inst 0xde01")
9420 #endif
9421
9422#elif defined(CATCH_PLATFORM_LINUX)
9423 // If we can use inline assembler, do it because this allows us to break
9424 // directly at the location of the failing check instead of breaking inside
9425 // raise() called from it, i.e. one stack frame below.
9426 #if defined(__GNUC__) && (defined(__i386) || defined(__x86_64))
9427 #define CATCH_TRAP() asm volatile ("int $3") /* NOLINT */
9428 #else // Fall back to the generic way.
9429 #include <signal.h>
9430
9431 #define CATCH_TRAP() raise(SIGTRAP)
9432 #endif
9433#elif defined(_MSC_VER)
9434 #define CATCH_TRAP() __debugbreak()
9435#elif defined(__MINGW32__)
9436 extern "C" __declspec(dllimport) void __stdcall DebugBreak();
9437 #define CATCH_TRAP() DebugBreak()
9438#endif
9439
9440#ifndef CATCH_BREAK_INTO_DEBUGGER
9441 #ifdef CATCH_TRAP
9442 #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }()
9443 #else
9444 #define CATCH_BREAK_INTO_DEBUGGER() []{}()
9445 #endif
9446#endif
9447
9448#endif // CATCH_DEBUGGER_HPP_INCLUDED
9449
9450
9451#ifndef CATCH_ENFORCE_HPP_INCLUDED
9452#define CATCH_ENFORCE_HPP_INCLUDED
9453
9454
9455#include <exception>
9456
9457namespace Catch {
9458#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
9459 template <typename Ex>
9460 [[noreturn]]
9461 void throw_exception(Ex const& e) {
9462 throw e;
9463 }
9464#else // ^^ Exceptions are enabled // Exceptions are disabled vv
9465 [[noreturn]]
9466 void throw_exception(std::exception const& e);
9467#endif
9468
9469 [[noreturn]]
9470 void throw_logic_error(std::string const& msg);
9471 [[noreturn]]
9472 void throw_domain_error(std::string const& msg);
9473 [[noreturn]]
9474 void throw_runtime_error(std::string const& msg);
9475
9476} // namespace Catch;
9477
9478#define CATCH_MAKE_MSG(...) \
9479 (Catch::ReusableStringStream() << __VA_ARGS__).str()
9480
9481#define CATCH_INTERNAL_ERROR(...) \
9482 Catch::throw_logic_error(CATCH_MAKE_MSG( CATCH_INTERNAL_LINEINFO << ": Internal Catch2 error: " << __VA_ARGS__))
9483
9484#define CATCH_ERROR(...) \
9485 Catch::throw_domain_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
9486
9487#define CATCH_RUNTIME_ERROR(...) \
9488 Catch::throw_runtime_error(CATCH_MAKE_MSG( __VA_ARGS__ ))
9489
9490#define CATCH_ENFORCE( condition, ... ) \
9491 do{ if( !(condition) ) CATCH_ERROR( __VA_ARGS__ ); } while(false)
9492
9493
9494#endif // CATCH_ENFORCE_HPP_INCLUDED
9495
9496
9497#ifndef CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
9498#define CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
9499
9500
9501#include <vector>
9502
9503namespace Catch {
9504
9505 namespace Detail {
9506
9507 Catch::Detail::unique_ptr<EnumInfo> makeEnumInfo( StringRef enumName, StringRef allValueNames, std::vector<int> const& values );
9508
9509 class EnumValuesRegistry : public IMutableEnumValuesRegistry {
9510
9511 std::vector<Catch::Detail::unique_ptr<EnumInfo>> m_enumInfos;
9512
9513 EnumInfo const& registerEnum( StringRef enumName, StringRef allValueNames, std::vector<int> const& values) override;
9514 };
9515
9516 std::vector<StringRef> parseEnums( StringRef enums );
9517
9518 } // Detail
9519
9520} // Catch
9521
9522#endif // CATCH_ENUM_VALUES_REGISTRY_HPP_INCLUDED
9523
9524
9525#ifndef CATCH_ERRNO_GUARD_HPP_INCLUDED
9526#define CATCH_ERRNO_GUARD_HPP_INCLUDED
9527
9528namespace Catch {
9529
9530 //! Simple RAII class that stores the value of `errno`
9531 //! at construction and restores it at destruction.
9532 class ErrnoGuard {
9533 public:
9534 // Keep these outlined to avoid dragging in macros from <cerrno>
9535
9536 ErrnoGuard();
9537 ~ErrnoGuard();
9538 private:
9539 int m_oldErrno;
9540 };
9541
9542}
9543
9544#endif // CATCH_ERRNO_GUARD_HPP_INCLUDED
9545
9546
9547#ifndef CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
9548#define CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
9549
9550
9551#include <vector>
9552#include <string>
9553
9554namespace Catch {
9555
9556 class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
9557 public:
9558 ~ExceptionTranslatorRegistry() override;
9559 void registerTranslator( Detail::unique_ptr<IExceptionTranslator>&& translator );
9560 std::string translateActiveException() const override;
9561
9562 private:
9563 ExceptionTranslators m_translators;
9564 };
9565}
9566
9567#endif // CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
9568
9569
9570#ifndef CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
9571#define CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
9572
9573#include <cassert>
9574
9575namespace Catch {
9576
9577 /**
9578 * Wrapper for platform-specific fatal error (signals/SEH) handlers
9579 *
9580 * Tries to be cooperative with other handlers, and not step over
9581 * other handlers. This means that unknown structured exceptions
9582 * are passed on, previous signal handlers are called, and so on.
9583 *
9584 * Can only be instantiated once, and assumes that once a signal
9585 * is caught, the binary will end up terminating. Thus, there
9586 */
9587 class FatalConditionHandler {
9588 bool m_started = false;
9589
9590 // Install/disengage implementation for specific platform.
9591 // Should be if-defed to work on current platform, can assume
9592 // engage-disengage 1:1 pairing.
9593 void engage_platform();
9594 void disengage_platform() noexcept;
9595 public:
9596 // Should also have platform-specific implementations as needed
9597 FatalConditionHandler();
9598 ~FatalConditionHandler();
9599
9600 void engage() {
9601 assert(!m_started && "Handler cannot be installed twice.");
9602 m_started = true;
9603 engage_platform();
9604 }
9605
9606 void disengage() noexcept {
9607 assert(m_started && "Handler cannot be uninstalled without being installed first");
9608 m_started = false;
9609 disengage_platform();
9610 }
9611 };
9612
9613 //! Simple RAII guard for (dis)engaging the FatalConditionHandler
9614 class FatalConditionHandlerGuard {
9615 FatalConditionHandler* m_handler;
9616 public:
9617 FatalConditionHandlerGuard(FatalConditionHandler* handler):
9618 m_handler(handler) {
9619 m_handler->engage();
9620 }
9621 ~FatalConditionHandlerGuard() {
9622 m_handler->disengage();
9623 }
9624 };
9625
9626} // end namespace Catch
9627
9628#endif // CATCH_FATAL_CONDITION_HANDLER_HPP_INCLUDED
9629
9630
9631#ifndef CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
9632#define CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
9633
9634
9635#include <cassert>
9636#include <cmath>
9637#include <cstdint>
9638#include <utility>
9639#include <limits>
9640
9641namespace Catch {
9642 namespace Detail {
9643
9644 uint32_t convertToBits(float f);
9645 uint64_t convertToBits(double d);
9646
9647 // Used when we know we want == comparison of two doubles
9648 // to centralize warning suppression
9649 bool directCompare( float lhs, float rhs );
9650 bool directCompare( double lhs, double rhs );
9651
9652 } // end namespace Detail
9653
9654
9655
9656#if defined( __GNUC__ ) || defined( __clang__ )
9657# pragma GCC diagnostic push
9658 // We do a bunch of direct compensations of floating point numbers,
9659 // because we know what we are doing and actually do want the direct
9660 // comparison behaviour.
9661# pragma GCC diagnostic ignored "-Wfloat-equal"
9662#endif
9663
9664 /**
9665 * Calculates the ULP distance between two floating point numbers
9666 *
9667 * The ULP distance of two floating point numbers is the count of
9668 * valid floating point numbers representable between them.
9669 *
9670 * There are some exceptions between how this function counts the
9671 * distance, and the interpretation of the standard as implemented.
9672 * by e.g. `nextafter`. For this function it always holds that:
9673 * * `(x == y) => ulpDistance(x, y) == 0` (so `ulpDistance(-0, 0) == 0`)
9674 * * `ulpDistance(maxFinite, INF) == 1`
9675 * * `ulpDistance(x, -x) == 2 * ulpDistance(x, 0)`
9676 *
9677 * \pre `!isnan( lhs )`
9678 * \pre `!isnan( rhs )`
9679 * \pre floating point numbers are represented in IEEE-754 format
9680 */
9681 template <typename FP>
9682 uint64_t ulpDistance( FP lhs, FP rhs ) {
9683 assert( std::numeric_limits<FP>::is_iec559 &&
9684 "ulpDistance assumes IEEE-754 format for floating point types" );
9685 assert( !Catch::isnan( lhs ) &&
9686 "Distance between NaN and number is not meaningful" );
9687 assert( !Catch::isnan( rhs ) &&
9688 "Distance between NaN and number is not meaningful" );
9689
9690 // We want X == Y to imply 0 ULP distance even if X and Y aren't
9691 // bit-equal (-0 and 0), or X - Y != 0 (same sign infinities).
9692 if ( lhs == rhs ) { return 0; }
9693
9694 // We need a properly typed positive zero for type inference.
9695 static constexpr FP positive_zero{};
9696
9697 // We want to ensure that +/- 0 is always represented as positive zero
9698 if ( lhs == positive_zero ) { lhs = positive_zero; }
9699 if ( rhs == positive_zero ) { rhs = positive_zero; }
9700
9701 // If arguments have different signs, we can handle them by summing
9702 // how far are they from 0 each.
9703 if ( std::signbit( lhs ) != std::signbit( rhs ) ) {
9704 return ulpDistance( std::abs( lhs ), positive_zero ) +
9705 ulpDistance( std::abs( rhs ), positive_zero );
9706 }
9707
9708 // When both lhs and rhs are of the same sign, we can just
9709 // read the numbers bitwise as integers, and then subtract them
9710 // (assuming IEEE).
9711 uint64_t lc = Detail::convertToBits( lhs );
9712 uint64_t rc = Detail::convertToBits( rhs );
9713
9714 // The ulp distance between two numbers is symmetric, so to avoid
9715 // dealing with overflows we want the bigger converted number on the lhs
9716 if ( lc < rc ) {
9717 std::swap( lc, rc );
9718 }
9719
9720 return lc - rc;
9721 }
9722
9723#if defined( __GNUC__ ) || defined( __clang__ )
9724# pragma GCC diagnostic pop
9725#endif
9726
9727
9728} // end namespace Catch
9729
9730#endif // CATCH_FLOATING_POINT_HELPERS_HPP_INCLUDED
9731
9732
9733#ifndef CATCH_GETENV_HPP_INCLUDED
9734#define CATCH_GETENV_HPP_INCLUDED
9735
9736namespace Catch {
9737namespace Detail {
9738
9739 //! Wrapper over `std::getenv` that compiles on UWP (and always returns nullptr there)
9740 char const* getEnv(char const* varName);
9741
9742}
9743}
9744
9745#endif // CATCH_GETENV_HPP_INCLUDED
9746
9747
9748#ifndef CATCH_IS_PERMUTATION_HPP_INCLUDED
9749#define CATCH_IS_PERMUTATION_HPP_INCLUDED
9750
9751#include <algorithm>
9752#include <iterator>
9753
9754namespace Catch {
9755 namespace Detail {
9756
9757 template <typename ForwardIter,
9758 typename Sentinel,
9759 typename T,
9760 typename Comparator>
9761 constexpr
9762 ForwardIter find_sentinel( ForwardIter start,
9763 Sentinel sentinel,
9764 T const& value,
9765 Comparator cmp ) {
9766 while ( start != sentinel ) {
9767 if ( cmp( *start, value ) ) { break; }
9768 ++start;
9769 }
9770 return start;
9771 }
9772
9773 template <typename ForwardIter,
9774 typename Sentinel,
9775 typename T,
9776 typename Comparator>
9777 constexpr
9778 std::ptrdiff_t count_sentinel( ForwardIter start,
9779 Sentinel sentinel,
9780 T const& value,
9781 Comparator cmp ) {
9782 std::ptrdiff_t count = 0;
9783 while ( start != sentinel ) {
9784 if ( cmp( *start, value ) ) { ++count; }
9785 ++start;
9786 }
9787 return count;
9788 }
9789
9790 template <typename ForwardIter, typename Sentinel>
9791 constexpr
9792 std::enable_if_t<!std::is_same<ForwardIter, Sentinel>::value,
9793 std::ptrdiff_t>
9794 sentinel_distance( ForwardIter iter, const Sentinel sentinel ) {
9795 std::ptrdiff_t dist = 0;
9796 while ( iter != sentinel ) {
9797 ++iter;
9798 ++dist;
9799 }
9800 return dist;
9801 }
9802
9803 template <typename ForwardIter>
9804 constexpr std::ptrdiff_t sentinel_distance( ForwardIter first,
9805 ForwardIter last ) {
9806 return std::distance( first, last );
9807 }
9808
9809 template <typename ForwardIter1,
9810 typename Sentinel1,
9811 typename ForwardIter2,
9812 typename Sentinel2,
9813 typename Comparator>
9814 constexpr bool check_element_counts( ForwardIter1 first_1,
9815 const Sentinel1 end_1,
9816 ForwardIter2 first_2,
9817 const Sentinel2 end_2,
9818 Comparator cmp ) {
9819 auto cursor = first_1;
9820 while ( cursor != end_1 ) {
9821 if ( find_sentinel( first_1, cursor, *cursor, cmp ) ==
9822 cursor ) {
9823 // we haven't checked this element yet
9824 const auto count_in_range_2 =
9825 count_sentinel( first_2, end_2, *cursor, cmp );
9826 // Not a single instance in 2nd range, so it cannot be a
9827 // permutation of 1st range
9828 if ( count_in_range_2 == 0 ) { return false; }
9829
9830 const auto count_in_range_1 =
9831 count_sentinel( cursor, end_1, *cursor, cmp );
9832 if ( count_in_range_1 != count_in_range_2 ) {
9833 return false;
9834 }
9835 }
9836
9837 ++cursor;
9838 }
9839
9840 return true;
9841 }
9842
9843 template <typename ForwardIter1,
9844 typename Sentinel1,
9845 typename ForwardIter2,
9846 typename Sentinel2,
9847 typename Comparator>
9848 constexpr bool is_permutation( ForwardIter1 first_1,
9849 const Sentinel1 end_1,
9850 ForwardIter2 first_2,
9851 const Sentinel2 end_2,
9852 Comparator cmp ) {
9853 // TODO: no optimization for stronger iterators, because we would also have to constrain on sentinel vs not sentinel types
9854 // TODO: Comparator has to be "both sides", e.g. a == b => b == a
9855 // This skips shared prefix of the two ranges
9856 while (first_1 != end_1 && first_2 != end_2 && cmp(*first_1, *first_2)) {
9857 ++first_1;
9858 ++first_2;
9859 }
9860
9861 // We need to handle case where at least one of the ranges has no more elements
9862 if (first_1 == end_1 || first_2 == end_2) {
9863 return first_1 == end_1 && first_2 == end_2;
9864 }
9865
9866 // pair counting is n**2, so we pay linear walk to compare the sizes first
9867 auto dist_1 = sentinel_distance( first_1, end_1 );
9868 auto dist_2 = sentinel_distance( first_2, end_2 );
9869
9870 if (dist_1 != dist_2) { return false; }
9871
9872 // Since we do not try to handle stronger iterators pair (e.g.
9873 // bidir) optimally, the only thing left to do is to check counts in
9874 // the remaining ranges.
9875 return check_element_counts( first_1, end_1, first_2, end_2, cmp );
9876 }
9877
9878 } // namespace Detail
9879} // namespace Catch
9880
9881#endif // CATCH_IS_PERMUTATION_HPP_INCLUDED
9882
9883
9884#ifndef CATCH_ISTREAM_HPP_INCLUDED
9885#define CATCH_ISTREAM_HPP_INCLUDED
9886
9887
9888#include <iosfwd>
9889#include <cstddef>
9890#include <ostream>
9891#include <string>
9892
9893namespace Catch {
9894
9895 class IStream {
9896 public:
9897 virtual ~IStream(); // = default
9898 virtual std::ostream& stream() = 0;
9899 /**
9900 * Best guess on whether the instance is writing to a console (e.g. via stdout/stderr)
9901 *
9902 * This is useful for e.g. Win32 colour support, because the Win32
9903 * API manipulates console directly, unlike POSIX escape codes,
9904 * that can be written anywhere.
9905 *
9906 * Due to variety of ways to change where the stdout/stderr is
9907 * _actually_ being written, users should always assume that
9908 * the answer might be wrong.
9909 */
9910 virtual bool isConsole() const { return false; }
9911 };
9912
9913 /**
9914 * Creates a stream wrapper that writes to specific file.
9915 *
9916 * Also recognizes 4 special filenames
9917 * * `-` for stdout
9918 * * `%stdout` for stdout
9919 * * `%stderr` for stderr
9920 * * `%debug` for platform specific debugging output
9921 *
9922 * \throws if passed an unrecognized %-prefixed stream
9923 */
9924 auto makeStream( std::string const& filename ) -> Detail::unique_ptr<IStream>;
9925
9926}
9927
9928#endif // CATCH_STREAM_HPP_INCLUDED
9929
9930
9931#ifndef CATCH_JSONWRITER_HPP_INCLUDED
9932#define CATCH_JSONWRITER_HPP_INCLUDED
9933
9934
9935#include <cstdint>
9936#include <sstream>
9937
9938namespace Catch {
9939 class JsonObjectWriter;
9940 class JsonArrayWriter;
9941
9942 struct JsonUtils {
9943 static void indent( std::ostream& os, std::uint64_t level );
9944 static void appendCommaNewline( std::ostream& os,
9945 bool& should_comma,
9946 std::uint64_t level );
9947 };
9948
9949 class JsonValueWriter {
9950 public:
9951 JsonValueWriter( std::ostream& os );
9952 JsonValueWriter( std::ostream& os, std::uint64_t indent_level );
9953
9954 JsonObjectWriter writeObject() &&;
9955 JsonArrayWriter writeArray() &&;
9956
9957 template <typename T>
9958 void write( T const& value ) && {
9959 writeImpl( value, !std::is_arithmetic<T>::value );
9960 }
9961 void write( StringRef value ) &&;
9962 void write( bool value ) &&;
9963
9964 private:
9965 void writeImpl( StringRef value, bool quote );
9966
9967 // Without this SFINAE, this overload is a better match
9968 // for `std::string`, `char const*`, `char const[N]` args.
9969 // While it would still work, it would cause code bloat
9970 // and multiple iteration over the strings
9971 template <typename T,
9972 typename = typename std::enable_if_t<
9973 !std::is_convertible<T, StringRef>::value>>
9974 void writeImpl( T const& value, bool quote_value ) {
9975 m_sstream << value;
9976 writeImpl( m_sstream.str(), quote_value );
9977 }
9978
9979 std::ostream& m_os;
9980 std::stringstream m_sstream;
9981 std::uint64_t m_indent_level;
9982 };
9983
9984 class JsonObjectWriter {
9985 public:
9986 JsonObjectWriter( std::ostream& os );
9987 JsonObjectWriter( std::ostream& os, std::uint64_t indent_level );
9988
9989 JsonObjectWriter( JsonObjectWriter&& source ) noexcept;
9990 JsonObjectWriter& operator=( JsonObjectWriter&& source ) = delete;
9991
9992 ~JsonObjectWriter();
9993
9994 JsonValueWriter write( StringRef key );
9995
9996 private:
9997 std::ostream& m_os;
9998 std::uint64_t m_indent_level;
9999 bool m_should_comma = false;
10000 bool m_active = true;
10001 };
10002
10003 class JsonArrayWriter {
10004 public:
10005 JsonArrayWriter( std::ostream& os );
10006 JsonArrayWriter( std::ostream& os, std::uint64_t indent_level );
10007
10008 JsonArrayWriter( JsonArrayWriter&& source ) noexcept;
10009 JsonArrayWriter& operator=( JsonArrayWriter&& source ) = delete;
10010
10011 ~JsonArrayWriter();
10012
10013 JsonObjectWriter writeObject();
10014 JsonArrayWriter writeArray();
10015
10016 template <typename T>
10017 JsonArrayWriter& write( T const& value ) {
10018 return writeImpl( value );
10019 }
10020
10021 JsonArrayWriter& write( bool value );
10022
10023 private:
10024 template <typename T>
10025 JsonArrayWriter& writeImpl( T const& value ) {
10026 JsonUtils::appendCommaNewline(
10027 m_os, m_should_comma, m_indent_level + 1 );
10028 JsonValueWriter{ m_os }.write( value );
10029
10030 return *this;
10031 }
10032
10033 std::ostream& m_os;
10034 std::uint64_t m_indent_level;
10035 bool m_should_comma = false;
10036 bool m_active = true;
10037 };
10038
10039} // namespace Catch
10040
10041#endif // CATCH_JSONWRITER_HPP_INCLUDED
10042
10043
10044#ifndef CATCH_LEAK_DETECTOR_HPP_INCLUDED
10045#define CATCH_LEAK_DETECTOR_HPP_INCLUDED
10046
10047namespace Catch {
10048
10049 struct LeakDetector {
10050 LeakDetector();
10051 ~LeakDetector();
10052 };
10053
10054}
10055#endif // CATCH_LEAK_DETECTOR_HPP_INCLUDED
10056
10057
10058#ifndef CATCH_LIST_HPP_INCLUDED
10059#define CATCH_LIST_HPP_INCLUDED
10060
10061
10062#include <set>
10063#include <string>
10064
10065
10066namespace Catch {
10067
10068 class IEventListener;
10069 class Config;
10070
10071
10072 struct ReporterDescription {
10073 std::string name, description;
10074 };
10075 struct ListenerDescription {
10076 StringRef name;
10077 std::string description;
10078 };
10079
10080 struct TagInfo {
10081 void add(StringRef spelling);
10082 std::string all() const;
10083
10084 std::set<StringRef> spellings;
10085 std::size_t count = 0;
10086 };
10087
10088 bool list( IEventListener& reporter, Config const& config );
10089
10090} // end namespace Catch
10091
10092#endif // CATCH_LIST_HPP_INCLUDED
10093
10094
10095#ifndef CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
10096#define CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
10097
10098
10099#include <cassert>
10100#include <string>
10101
10102namespace Catch {
10103
10104 class OutputRedirect {
10105 bool m_redirectActive = false;
10106 virtual void activateImpl() = 0;
10107 virtual void deactivateImpl() = 0;
10108 public:
10109 enum Kind {
10110 //! No redirect (noop implementation)
10111 None,
10112 //! Redirect std::cout/std::cerr/std::clog streams internally
10113 Streams,
10114 //! Redirect the stdout/stderr file descriptors into files
10115 FileDescriptors,
10116 };
10117
10118 virtual ~OutputRedirect(); // = default;
10119
10120 // TODO: Do we want to check that redirect is not active before retrieving the output?
10121 virtual std::string getStdout() = 0;
10122 virtual std::string getStderr() = 0;
10123 virtual void clearBuffers() = 0;
10124 bool isActive() const { return m_redirectActive; }
10125 void activate() {
10126 assert( !m_redirectActive && "redirect is already active" );
10127 activateImpl();
10128 m_redirectActive = true;
10129 }
10130 void deactivate() {
10131 assert( m_redirectActive && "redirect is not active" );
10132 deactivateImpl();
10133 m_redirectActive = false;
10134 }
10135 };
10136
10137 bool isRedirectAvailable( OutputRedirect::Kind kind);
10138 Detail::unique_ptr<OutputRedirect> makeOutputRedirect( bool actual );
10139
10140 class RedirectGuard {
10141 OutputRedirect* m_redirect;
10142 bool m_activate;
10143 bool m_previouslyActive;
10144 bool m_moved = false;
10145
10146 public:
10147 RedirectGuard( bool activate, OutputRedirect& redirectImpl );
10148 ~RedirectGuard() noexcept( false );
10149
10150 RedirectGuard( RedirectGuard const& ) = delete;
10151 RedirectGuard& operator=( RedirectGuard const& ) = delete;
10152
10153 // C++14 needs move-able guards to return them from functions
10154 RedirectGuard( RedirectGuard&& rhs ) noexcept;
10155 RedirectGuard& operator=( RedirectGuard&& rhs ) noexcept;
10156 };
10157
10158 RedirectGuard scopedActivate( OutputRedirect& redirectImpl );
10159 RedirectGuard scopedDeactivate( OutputRedirect& redirectImpl );
10160
10161} // end namespace Catch
10162
10163#endif // CATCH_OUTPUT_REDIRECT_HPP_INCLUDED
10164
10165
10166#ifndef CATCH_PARSE_NUMBERS_HPP_INCLUDED
10167#define CATCH_PARSE_NUMBERS_HPP_INCLUDED
10168
10169
10170#include <string>
10171
10172namespace Catch {
10173
10174 /**
10175 * Parses unsigned int from the input, using provided base
10176 *
10177 * Effectively a wrapper around std::stoul but with better error checking
10178 * e.g. "-1" is rejected, instead of being parsed as UINT_MAX.
10179 */
10180 Optional<unsigned int> parseUInt(std::string const& input, int base = 10);
10181}
10182
10183#endif // CATCH_PARSE_NUMBERS_HPP_INCLUDED
10184
10185
10186#ifndef CATCH_REPORTER_REGISTRY_HPP_INCLUDED
10187#define CATCH_REPORTER_REGISTRY_HPP_INCLUDED
10188
10189
10190#include <map>
10191#include <string>
10192#include <vector>
10193
10194namespace Catch {
10195
10196 class IEventListener;
10197 using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
10198 class IReporterFactory;
10199 using IReporterFactoryPtr = Detail::unique_ptr<IReporterFactory>;
10200 struct ReporterConfig;
10201 class EventListenerFactory;
10202
10203 class ReporterRegistry {
10204 struct ReporterRegistryImpl;
10205 Detail::unique_ptr<ReporterRegistryImpl> m_impl;
10206
10207 public:
10208 ReporterRegistry();
10209 ~ReporterRegistry(); // = default;
10210
10211 IEventListenerPtr create( std::string const& name,
10212 ReporterConfig&& config ) const;
10213
10214 void registerReporter( std::string const& name,
10215 IReporterFactoryPtr factory );
10216
10217 void
10218 registerListener( Detail::unique_ptr<EventListenerFactory> factory );
10219
10220 std::map<std::string,
10221 IReporterFactoryPtr,
10222 Detail::CaseInsensitiveLess> const&
10223 getFactories() const;
10224
10225 std::vector<Detail::unique_ptr<EventListenerFactory>> const&
10226 getListeners() const;
10227 };
10228
10229} // end namespace Catch
10230
10231#endif // CATCH_REPORTER_REGISTRY_HPP_INCLUDED
10232
10233
10234#ifndef CATCH_RUN_CONTEXT_HPP_INCLUDED
10235#define CATCH_RUN_CONTEXT_HPP_INCLUDED
10236
10237
10238
10239#ifndef CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
10240#define CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
10241
10242
10243#include <string>
10244#include <vector>
10245
10246namespace Catch {
10247namespace TestCaseTracking {
10248
10249 struct NameAndLocation {
10250 std::string name;
10251 SourceLineInfo location;
10252
10253 NameAndLocation( std::string&& _name, SourceLineInfo const& _location );
10254 friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) {
10255 // This is a very cheap check that should have a very high hit rate.
10256 // If we get to SourceLineInfo::operator==, we will redo it, but the
10257 // cost of repeating is trivial at that point (we will be paying
10258 // multiple strcmp/memcmps at that point).
10259 if ( lhs.location.line != rhs.location.line ) { return false; }
10260 return lhs.name == rhs.name && lhs.location == rhs.location;
10261 }
10262 friend bool operator!=(NameAndLocation const& lhs,
10263 NameAndLocation const& rhs) {
10264 return !( lhs == rhs );
10265 }
10266 };
10267
10268 /**
10269 * This is a variant of `NameAndLocation` that does not own the name string
10270 *
10271 * This avoids extra allocations when trying to locate a tracker by its
10272 * name and location, as long as we make sure that trackers only keep
10273 * around the owning variant.
10274 */
10275 struct NameAndLocationRef {
10276 StringRef name;
10277 SourceLineInfo location;
10278
10279 constexpr NameAndLocationRef( StringRef name_,
10280 SourceLineInfo location_ ):
10281 name( name_ ), location( location_ ) {}
10282
10283 friend bool operator==( NameAndLocation const& lhs,
10284 NameAndLocationRef const& rhs ) {
10285 // This is a very cheap check that should have a very high hit rate.
10286 // If we get to SourceLineInfo::operator==, we will redo it, but the
10287 // cost of repeating is trivial at that point (we will be paying
10288 // multiple strcmp/memcmps at that point).
10289 if ( lhs.location.line != rhs.location.line ) { return false; }
10290 return StringRef( lhs.name ) == rhs.name &&
10291 lhs.location == rhs.location;
10292 }
10293 friend bool operator==( NameAndLocationRef const& lhs,
10294 NameAndLocation const& rhs ) {
10295 return rhs == lhs;
10296 }
10297 };
10298
10299 class ITracker;
10300
10301 using ITrackerPtr = Catch::Detail::unique_ptr<ITracker>;
10302
10303 class ITracker {
10304 NameAndLocation m_nameAndLocation;
10305
10306 using Children = std::vector<ITrackerPtr>;
10307
10308 protected:
10309 enum CycleState {
10310 NotStarted,
10311 Executing,
10312 ExecutingChildren,
10313 NeedsAnotherRun,
10314 CompletedSuccessfully,
10315 Failed
10316 };
10317
10318 ITracker* m_parent = nullptr;
10319 Children m_children;
10320 CycleState m_runState = NotStarted;
10321
10322 public:
10323 ITracker( NameAndLocation&& nameAndLoc, ITracker* parent ):
10324 m_nameAndLocation( CATCH_MOVE(nameAndLoc) ),
10325 m_parent( parent )
10326 {}
10327
10328
10329 // static queries
10330 NameAndLocation const& nameAndLocation() const {
10331 return m_nameAndLocation;
10332 }
10333 ITracker* parent() const {
10334 return m_parent;
10335 }
10336
10337 virtual ~ITracker(); // = default
10338
10339
10340 // dynamic queries
10341
10342 //! Returns true if tracker run to completion (successfully or not)
10343 virtual bool isComplete() const = 0;
10344 //! Returns true if tracker run to completion successfully
10345 bool isSuccessfullyCompleted() const {
10346 return m_runState == CompletedSuccessfully;
10347 }
10348 //! Returns true if tracker has started but hasn't been completed
10349 bool isOpen() const;
10350 //! Returns true iff tracker has started
10351 bool hasStarted() const;
10352
10353 // actions
10354 virtual void close() = 0; // Successfully complete
10355 virtual void fail() = 0;
10356 void markAsNeedingAnotherRun();
10357
10358 //! Register a nested ITracker
10359 void addChild( ITrackerPtr&& child );
10360 /**
10361 * Returns ptr to specific child if register with this tracker.
10362 *
10363 * Returns nullptr if not found.
10364 */
10365 ITracker* findChild( NameAndLocationRef const& nameAndLocation );
10366 //! Have any children been added?
10367 bool hasChildren() const {
10368 return !m_children.empty();
10369 }
10370
10371
10372 //! Marks tracker as executing a child, doing se recursively up the tree
10373 void openChild();
10374
10375 /**
10376 * Returns true if the instance is a section tracker
10377 *
10378 * Subclasses should override to true if they are, replaces RTTI
10379 * for internal debug checks.
10380 */
10381 virtual bool isSectionTracker() const;
10382 /**
10383 * Returns true if the instance is a generator tracker
10384 *
10385 * Subclasses should override to true if they are, replaces RTTI
10386 * for internal debug checks.
10387 */
10388 virtual bool isGeneratorTracker() const;
10389 };
10390
10391 class TrackerContext {
10392
10393 enum RunState {
10394 NotStarted,
10395 Executing,
10396 CompletedCycle
10397 };
10398
10399 ITrackerPtr m_rootTracker;
10400 ITracker* m_currentTracker = nullptr;
10401 RunState m_runState = NotStarted;
10402
10403 public:
10404
10405 ITracker& startRun();
10406
10407 void startCycle() {
10408 m_currentTracker = m_rootTracker.get();
10409 m_runState = Executing;
10410 }
10411 void completeCycle();
10412
10413 bool completedCycle() const;
10414 ITracker& currentTracker() { return *m_currentTracker; }
10415 void setCurrentTracker( ITracker* tracker );
10416 };
10417
10418 class TrackerBase : public ITracker {
10419 protected:
10420
10421 TrackerContext& m_ctx;
10422
10423 public:
10424 TrackerBase( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
10425
10426 bool isComplete() const override;
10427
10428 void open();
10429
10430 void close() override;
10431 void fail() override;
10432
10433 private:
10434 void moveToParent();
10435 void moveToThis();
10436 };
10437
10438 class SectionTracker : public TrackerBase {
10439 std::vector<StringRef> m_filters;
10440 // Note that lifetime-wise we piggy back off the name stored in the `ITracker` parent`.
10441 // Currently it allocates owns the name, so this is safe. If it is later refactored
10442 // to not own the name, the name still has to outlive the `ITracker` parent, so
10443 // this should still be safe.
10444 StringRef m_trimmed_name;
10445 public:
10446 SectionTracker( NameAndLocation&& nameAndLocation, TrackerContext& ctx, ITracker* parent );
10447
10448 bool isSectionTracker() const override;
10449
10450 bool isComplete() const override;
10451
10452 static SectionTracker& acquire( TrackerContext& ctx, NameAndLocationRef const& nameAndLocation );
10453
10454 void tryOpen();
10455
10456 void addInitialFilters( std::vector<std::string> const& filters );
10457 void addNextFilters( std::vector<StringRef> const& filters );
10458 //! Returns filters active in this tracker
10459 std::vector<StringRef> const& getFilters() const { return m_filters; }
10460 //! Returns whitespace-trimmed name of the tracked section
10461 StringRef trimmedName() const;
10462 };
10463
10464} // namespace TestCaseTracking
10465
10466using TestCaseTracking::ITracker;
10467using TestCaseTracking::TrackerContext;
10468using TestCaseTracking::SectionTracker;
10469
10470} // namespace Catch
10471
10472#endif // CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
10473
10474#include <string>
10475
10476namespace Catch {
10477
10478 class IGeneratorTracker;
10479 class IConfig;
10480 class IEventListener;
10481 using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
10482 class OutputRedirect;
10483
10484 ///////////////////////////////////////////////////////////////////////////
10485
10486 class RunContext final : public IResultCapture {
10487
10488 public:
10489 RunContext( RunContext const& ) = delete;
10490 RunContext& operator =( RunContext const& ) = delete;
10491
10492 explicit RunContext( IConfig const* _config, IEventListenerPtr&& reporter );
10493
10494 ~RunContext() override;
10495
10496 Totals runTest(TestCaseHandle const& testCase);
10497
10498 public: // IResultCapture
10499
10500 // Assertion handlers
10501 void handleExpr
10502 ( AssertionInfo const& info,
10503 ITransientExpression const& expr,
10504 AssertionReaction& reaction ) override;
10505 void handleMessage
10506 ( AssertionInfo const& info,
10507 ResultWas::OfType resultType,
10508 std::string&& message,
10509 AssertionReaction& reaction ) override;
10510 void handleUnexpectedExceptionNotThrown
10511 ( AssertionInfo const& info,
10512 AssertionReaction& reaction ) override;
10513 void handleUnexpectedInflightException
10514 ( AssertionInfo const& info,
10515 std::string&& message,
10516 AssertionReaction& reaction ) override;
10517 void handleIncomplete
10518 ( AssertionInfo const& info ) override;
10519 void handleNonExpr
10520 ( AssertionInfo const &info,
10521 ResultWas::OfType resultType,
10522 AssertionReaction &reaction ) override;
10523
10524 void notifyAssertionStarted( AssertionInfo const& info ) override;
10525 bool sectionStarted( StringRef sectionName,
10526 SourceLineInfo const& sectionLineInfo,
10527 Counts& assertions ) override;
10528
10529 void sectionEnded( SectionEndInfo&& endInfo ) override;
10530 void sectionEndedEarly( SectionEndInfo&& endInfo ) override;
10531
10532 IGeneratorTracker*
10533 acquireGeneratorTracker( StringRef generatorName,
10534 SourceLineInfo const& lineInfo ) override;
10535 IGeneratorTracker* createGeneratorTracker(
10536 StringRef generatorName,
10537 SourceLineInfo lineInfo,
10538 Generators::GeneratorBasePtr&& generator ) override;
10539
10540
10541 void benchmarkPreparing( StringRef name ) override;
10542 void benchmarkStarting( BenchmarkInfo const& info ) override;
10543 void benchmarkEnded( BenchmarkStats<> const& stats ) override;
10544 void benchmarkFailed( StringRef error ) override;
10545
10546 void pushScopedMessage( MessageInfo const& message ) override;
10547 void popScopedMessage( MessageInfo const& message ) override;
10548
10549 void emplaceUnscopedMessage( MessageBuilder&& builder ) override;
10550
10551 std::string getCurrentTestName() const override;
10552
10553 const AssertionResult* getLastResult() const override;
10554
10555 void exceptionEarlyReported() override;
10556
10557 void handleFatalErrorCondition( StringRef message ) override;
10558
10559 bool lastAssertionPassed() override;
10560
10561 void assertionPassed() override;
10562
10563 public:
10564 // !TBD We need to do this another way!
10565 bool aborting() const;
10566
10567 private:
10568
10569 void runCurrentTest();
10570 void invokeActiveTestCase();
10571
10572 void resetAssertionInfo();
10573 bool testForMissingAssertions( Counts& assertions );
10574
10575 void assertionEnded( AssertionResult&& result );
10576 void reportExpr
10577 ( AssertionInfo const &info,
10578 ResultWas::OfType resultType,
10579 ITransientExpression const *expr,
10580 bool negated );
10581
10582 void populateReaction( AssertionReaction& reaction );
10583
10584 private:
10585
10586 void handleUnfinishedSections();
10587
10588 TestRunInfo m_runInfo;
10589 TestCaseHandle const* m_activeTestCase = nullptr;
10590 ITracker* m_testCaseTracker = nullptr;
10591 Optional<AssertionResult> m_lastResult;
10592
10593 IConfig const* m_config;
10594 Totals m_totals;
10595 IEventListenerPtr m_reporter;
10596 std::vector<MessageInfo> m_messages;
10597 std::vector<ScopedMessage> m_messageScopes; /* Keeps owners of so-called unscoped messages. */
10598 AssertionInfo m_lastAssertionInfo;
10599 std::vector<SectionEndInfo> m_unfinishedSections;
10600 std::vector<ITracker*> m_activeSections;
10601 TrackerContext m_trackerContext;
10602 Detail::unique_ptr<OutputRedirect> m_outputRedirect;
10603 FatalConditionHandler m_fatalConditionhandler;
10604 bool m_lastAssertionPassed = false;
10605 bool m_shouldReportUnexpected = true;
10606 bool m_includeSuccessfulResults;
10607 };
10608
10609 void seedRng(IConfig const& config);
10610 unsigned int rngSeed();
10611} // end namespace Catch
10612
10613#endif // CATCH_RUN_CONTEXT_HPP_INCLUDED
10614
10615
10616#ifndef CATCH_SHARDING_HPP_INCLUDED
10617#define CATCH_SHARDING_HPP_INCLUDED
10618
10619#include <cassert>
10620#include <cmath>
10621#include <algorithm>
10622
10623namespace Catch {
10624
10625 template<typename Container>
10626 Container createShard(Container const& container, std::size_t const shardCount, std::size_t const shardIndex) {
10627 assert(shardCount > shardIndex);
10628
10629 if (shardCount == 1) {
10630 return container;
10631 }
10632
10633 const std::size_t totalTestCount = container.size();
10634
10635 const std::size_t shardSize = totalTestCount / shardCount;
10636 const std::size_t leftoverTests = totalTestCount % shardCount;
10637
10638 const std::size_t startIndex = shardIndex * shardSize + (std::min)(shardIndex, leftoverTests);
10639 const std::size_t endIndex = (shardIndex + 1) * shardSize + (std::min)(shardIndex + 1, leftoverTests);
10640
10641 auto startIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(startIndex));
10642 auto endIterator = std::next(container.begin(), static_cast<std::ptrdiff_t>(endIndex));
10643
10644 return Container(startIterator, endIterator);
10645 }
10646
10647}
10648
10649#endif // CATCH_SHARDING_HPP_INCLUDED
10650
10651
10652#ifndef CATCH_SINGLETONS_HPP_INCLUDED
10653#define CATCH_SINGLETONS_HPP_INCLUDED
10654
10655namespace Catch {
10656
10657 struct ISingleton {
10658 virtual ~ISingleton(); // = default
10659 };
10660
10661
10662 void addSingleton( ISingleton* singleton );
10663 void cleanupSingletons();
10664
10665
10666 template<typename SingletonImplT, typename InterfaceT = SingletonImplT, typename MutableInterfaceT = InterfaceT>
10667 class Singleton : SingletonImplT, public ISingleton {
10668
10669 static auto getInternal() -> Singleton* {
10670 static Singleton* s_instance = nullptr;
10671 if( !s_instance ) {
10672 s_instance = new Singleton;
10673 addSingleton( s_instance );
10674 }
10675 return s_instance;
10676 }
10677
10678 public:
10679 static auto get() -> InterfaceT const& {
10680 return *getInternal();
10681 }
10682 static auto getMutable() -> MutableInterfaceT& {
10683 return *getInternal();
10684 }
10685 };
10686
10687} // namespace Catch
10688
10689#endif // CATCH_SINGLETONS_HPP_INCLUDED
10690
10691
10692#ifndef CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
10693#define CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
10694
10695
10696#include <vector>
10697#include <exception>
10698
10699namespace Catch {
10700
10701 class StartupExceptionRegistry {
10702#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
10703 public:
10704 void add(std::exception_ptr const& exception) noexcept;
10705 std::vector<std::exception_ptr> const& getExceptions() const noexcept;
10706 private:
10707 std::vector<std::exception_ptr> m_exceptions;
10708#endif
10709 };
10710
10711} // end namespace Catch
10712
10713#endif // CATCH_STARTUP_EXCEPTION_REGISTRY_HPP_INCLUDED
10714
10715
10716
10717#ifndef CATCH_STDSTREAMS_HPP_INCLUDED
10718#define CATCH_STDSTREAMS_HPP_INCLUDED
10719
10720#include <iosfwd>
10721
10722namespace Catch {
10723
10724 std::ostream& cout();
10725 std::ostream& cerr();
10726 std::ostream& clog();
10727
10728} // namespace Catch
10729
10730#endif
10731
10732
10733#ifndef CATCH_STRING_MANIP_HPP_INCLUDED
10734#define CATCH_STRING_MANIP_HPP_INCLUDED
10735
10736
10737#include <cstdint>
10738#include <string>
10739#include <iosfwd>
10740#include <vector>
10741
10742namespace Catch {
10743
10744 bool startsWith( std::string const& s, std::string const& prefix );
10745 bool startsWith( StringRef s, char prefix );
10746 bool endsWith( std::string const& s, std::string const& suffix );
10747 bool endsWith( std::string const& s, char suffix );
10748 bool contains( std::string const& s, std::string const& infix );
10749 void toLowerInPlace( std::string& s );
10750 std::string toLower( std::string const& s );
10751 char toLower( char c );
10752 //! Returns a new string without whitespace at the start/end
10753 std::string trim( std::string const& str );
10754 //! Returns a substring of the original ref without whitespace. Beware lifetimes!
10755 StringRef trim(StringRef ref);
10756
10757 // !!! Be aware, returns refs into original string - make sure original string outlives them
10758 std::vector<StringRef> splitStringRef( StringRef str, char delimiter );
10759 bool replaceInPlace( std::string& str, std::string const& replaceThis, std::string const& withThis );
10760
10761 /**
10762 * Helper for streaming a "count [maybe-plural-of-label]" human-friendly string
10763 *
10764 * Usage example:
10765 * ```cpp
10766 * std::cout << "Found " << pluralise(count, "error") << '\n';
10767 * ```
10768 *
10769 * **Important:** The provided string must outlive the instance
10770 */
10771 class pluralise {
10772 std::uint64_t m_count;
10773 StringRef m_label;
10774
10775 public:
10776 constexpr pluralise(std::uint64_t count, StringRef label):
10777 m_count(count),
10778 m_label(label)
10779 {}
10780
10781 friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
10782 };
10783}
10784
10785#endif // CATCH_STRING_MANIP_HPP_INCLUDED
10786
10787
10788#ifndef CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
10789#define CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
10790
10791
10792#include <map>
10793#include <string>
10794
10795namespace Catch {
10796 struct SourceLineInfo;
10797
10798 class TagAliasRegistry : public ITagAliasRegistry {
10799 public:
10800 ~TagAliasRegistry() override;
10801 TagAlias const* find( std::string const& alias ) const override;
10802 std::string expandAliases( std::string const& unexpandedTestSpec ) const override;
10803 void add( std::string const& alias, std::string const& tag, SourceLineInfo const& lineInfo );
10804
10805 private:
10806 std::map<std::string, TagAlias> m_registry;
10807 };
10808
10809} // end namespace Catch
10810
10811#endif // CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
10812
10813
10814#ifndef CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
10815#define CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED
10816
10817#include <cstdint>
10818
10819namespace Catch {
10820
10821 struct TestCaseInfo;
10822
10823 class TestCaseInfoHasher {
10824 public:
10825 using hash_t = std::uint64_t;
10826 TestCaseInfoHasher( hash_t seed );
10827 uint32_t operator()( TestCaseInfo const& t ) const;
10828
10829 private:
10830 hash_t m_seed;
10831 };
10832
10833} // namespace Catch
10834
10835#endif /* CATCH_TEST_CASE_INFO_HASHER_HPP_INCLUDED */
10836
10837
10838#ifndef CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
10839#define CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
10840
10841
10842#include <vector>
10843
10844namespace Catch {
10845
10846 class IConfig;
10847 class ITestInvoker;
10848 class TestCaseHandle;
10849 class TestSpec;
10850
10851 std::vector<TestCaseHandle> sortTests( IConfig const& config, std::vector<TestCaseHandle> const& unsortedTestCases );
10852
10853 bool isThrowSafe( TestCaseHandle const& testCase, IConfig const& config );
10854
10855 std::vector<TestCaseHandle> filterTests( std::vector<TestCaseHandle> const& testCases, TestSpec const& testSpec, IConfig const& config );
10856 std::vector<TestCaseHandle> const& getAllTestCasesSorted( IConfig const& config );
10857
10858 class TestRegistry : public ITestCaseRegistry {
10859 public:
10860 void registerTest( Detail::unique_ptr<TestCaseInfo> testInfo, Detail::unique_ptr<ITestInvoker> testInvoker );
10861
10862 std::vector<TestCaseInfo*> const& getAllInfos() const override;
10863 std::vector<TestCaseHandle> const& getAllTests() const override;
10864 std::vector<TestCaseHandle> const& getAllTestsSorted( IConfig const& config ) const override;
10865
10866 ~TestRegistry() override; // = default
10867
10868 private:
10869 std::vector<Detail::unique_ptr<TestCaseInfo>> m_owned_test_infos;
10870 // Keeps a materialized vector for `getAllInfos`.
10871 // We should get rid of that eventually (see interface note)
10872 std::vector<TestCaseInfo*> m_viewed_test_infos;
10873
10874 std::vector<Detail::unique_ptr<ITestInvoker>> m_invokers;
10875 std::vector<TestCaseHandle> m_handles;
10876 mutable TestRunOrder m_currentSortOrder = TestRunOrder::Declared;
10877 mutable std::vector<TestCaseHandle> m_sortedFunctions;
10878 };
10879
10880 ///////////////////////////////////////////////////////////////////////////
10881
10882
10883} // end namespace Catch
10884
10885
10886#endif // CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
10887
10888
10889#ifndef CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
10890#define CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
10891
10892#ifdef __clang__
10893#pragma clang diagnostic push
10894#pragma clang diagnostic ignored "-Wpadded"
10895#endif
10896
10897
10898#include <vector>
10899#include <string>
10900
10901namespace Catch {
10902
10903 class ITagAliasRegistry;
10904
10905 class TestSpecParser {
10906 enum Mode{ None, Name, QuotedName, Tag, EscapedName };
10907 Mode m_mode = None;
10908 Mode lastMode = None;
10909 bool m_exclusion = false;
10910 std::size_t m_pos = 0;
10911 std::size_t m_realPatternPos = 0;
10912 std::string m_arg;
10913 std::string m_substring;
10914 std::string m_patternName;
10915 std::vector<std::size_t> m_escapeChars;
10916 TestSpec::Filter m_currentFilter;
10917 TestSpec m_testSpec;
10918 ITagAliasRegistry const* m_tagAliases = nullptr;
10919
10920 public:
10921 TestSpecParser( ITagAliasRegistry const& tagAliases );
10922
10923 TestSpecParser& parse( std::string const& arg );
10924 TestSpec testSpec();
10925
10926 private:
10927 bool visitChar( char c );
10928 void startNewMode( Mode mode );
10929 bool processNoneChar( char c );
10930 void processNameChar( char c );
10931 bool processOtherChar( char c );
10932 void endMode();
10933 void escape();
10934 bool isControlChar( char c ) const;
10935 void saveLastMode();
10936 void revertBackToLastMode();
10937 void addFilter();
10938 bool separate();
10939
10940 // Handles common preprocessing of the pattern for name/tag patterns
10941 std::string preprocessPattern();
10942 // Adds the current pattern as a test name
10943 void addNamePattern();
10944 // Adds the current pattern as a tag
10945 void addTagPattern();
10946
10947 inline void addCharToPattern(char c) {
10948 m_substring += c;
10949 m_patternName += c;
10950 m_realPatternPos++;
10951 }
10952
10953 };
10954
10955} // namespace Catch
10956
10957#ifdef __clang__
10958#pragma clang diagnostic pop
10959#endif
10960
10961#endif // CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
10962
10963
10964#ifndef CATCH_TEXTFLOW_HPP_INCLUDED
10965#define CATCH_TEXTFLOW_HPP_INCLUDED
10966
10967
10968#include <cassert>
10969#include <string>
10970#include <vector>
10971
10972namespace Catch {
10973 namespace TextFlow {
10974
10975 class Columns;
10976
10977 /**
10978 * Abstraction for a string with ansi escape sequences that
10979 * automatically skips over escapes when iterating. Only graphical
10980 * escape sequences are considered.
10981 *
10982 * Internal representation:
10983 * An escape sequence looks like \033[39;49m
10984 * We need bidirectional iteration and the unbound length of escape
10985 * sequences poses a problem for operator-- To make this work we'll
10986 * replace the last `m` with a 0xff (this is a codepoint that won't have
10987 * any utf-8 meaning).
10988 */
10989 class AnsiSkippingString {
10990 std::string m_string;
10991 std::size_t m_size = 0;
10992
10993 // perform 0xff replacement and calculate m_size
10994 void preprocessString();
10995
10996 public:
10997 class const_iterator;
10998 using iterator = const_iterator;
10999 // note: must be u-suffixed or this will cause a "truncation of
11000 // constant value" warning on MSVC
11001 static constexpr char sentinel = static_cast<char>( 0xffu );
11002
11003 explicit AnsiSkippingString( std::string const& text );
11004 explicit AnsiSkippingString( std::string&& text );
11005
11006 const_iterator begin() const;
11007 const_iterator end() const;
11008
11009 size_t size() const { return m_size; }
11010
11011 std::string substring( const_iterator begin,
11012 const_iterator end ) const;
11013 };
11014
11015 class AnsiSkippingString::const_iterator {
11016 friend AnsiSkippingString;
11017 struct EndTag {};
11018
11019 const std::string* m_string;
11020 std::string::const_iterator m_it;
11021
11022 explicit const_iterator( const std::string& string, EndTag ):
11023 m_string( &string ), m_it( string.end() ) {}
11024
11025 void tryParseAnsiEscapes();
11026 void advance();
11027 void unadvance();
11028
11029 public:
11030 using difference_type = std::ptrdiff_t;
11031 using value_type = char;
11032 using pointer = value_type*;
11033 using reference = value_type&;
11034 using iterator_category = std::bidirectional_iterator_tag;
11035
11036 explicit const_iterator( const std::string& string ):
11037 m_string( &string ), m_it( string.begin() ) {
11038 tryParseAnsiEscapes();
11039 }
11040
11041 char operator*() const { return *m_it; }
11042
11043 const_iterator& operator++() {
11044 advance();
11045 return *this;
11046 }
11047 const_iterator operator++( int ) {
11048 iterator prev( *this );
11049 operator++();
11050 return prev;
11051 }
11052 const_iterator& operator--() {
11053 unadvance();
11054 return *this;
11055 }
11056 const_iterator operator--( int ) {
11057 iterator prev( *this );
11058 operator--();
11059 return prev;
11060 }
11061
11062 bool operator==( const_iterator const& other ) const {
11063 return m_it == other.m_it;
11064 }
11065 bool operator!=( const_iterator const& other ) const {
11066 return !operator==( other );
11067 }
11068 bool operator<=( const_iterator const& other ) const {
11069 return m_it <= other.m_it;
11070 }
11071
11072 const_iterator oneBefore() const {
11073 auto it = *this;
11074 return --it;
11075 }
11076 };
11077
11078 /**
11079 * Represents a column of text with specific width and indentation
11080 *
11081 * When written out to a stream, it will perform linebreaking
11082 * of the provided text so that the written lines fit within
11083 * target width.
11084 */
11085 class Column {
11086 // String to be written out
11087 AnsiSkippingString m_string;
11088 // Width of the column for linebreaking
11089 size_t m_width = CATCH_CONFIG_CONSOLE_WIDTH - 1;
11090 // Indentation of other lines (including first if initial indent is
11091 // unset)
11092 size_t m_indent = 0;
11093 // Indentation of the first line
11094 size_t m_initialIndent = std::string::npos;
11095
11096 public:
11097 /**
11098 * Iterates "lines" in `Column` and returns them
11099 */
11100 class const_iterator {
11101 friend Column;
11102 struct EndTag {};
11103
11104 Column const& m_column;
11105 // Where does the current line start?
11106 AnsiSkippingString::const_iterator m_lineStart;
11107 // How long should the current line be?
11108 AnsiSkippingString::const_iterator m_lineEnd;
11109 // How far have we checked the string to iterate?
11110 AnsiSkippingString::const_iterator m_parsedTo;
11111 // Should a '-' be appended to the line?
11112 bool m_addHyphen = false;
11113
11114 const_iterator( Column const& column, EndTag ):
11115 m_column( column ),
11116 m_lineStart( m_column.m_string.end() ),
11117 m_lineEnd( column.m_string.end() ),
11118 m_parsedTo( column.m_string.end() ) {}
11119
11120 // Calculates the length of the current line
11121 void calcLength();
11122
11123 // Returns current indentation width
11124 size_t indentSize() const;
11125
11126 // Creates an indented and (optionally) suffixed string from
11127 // current iterator position, indentation and length.
11128 std::string addIndentAndSuffix(
11129 AnsiSkippingString::const_iterator start,
11130 AnsiSkippingString::const_iterator end ) const;
11131
11132 public:
11133 using difference_type = std::ptrdiff_t;
11134 using value_type = std::string;
11135 using pointer = value_type*;
11136 using reference = value_type&;
11137 using iterator_category = std::forward_iterator_tag;
11138
11139 explicit const_iterator( Column const& column );
11140
11141 std::string operator*() const;
11142
11143 const_iterator& operator++();
11144 const_iterator operator++( int );
11145
11146 bool operator==( const_iterator const& other ) const {
11147 return m_lineStart == other.m_lineStart &&
11148 &m_column == &other.m_column;
11149 }
11150 bool operator!=( const_iterator const& other ) const {
11151 return !operator==( other );
11152 }
11153 };
11154 using iterator = const_iterator;
11155
11156 explicit Column( std::string const& text ): m_string( text ) {}
11157 explicit Column( std::string&& text ):
11158 m_string( CATCH_MOVE( text ) ) {}
11159
11160 Column& width( size_t newWidth ) & {
11161 assert( newWidth > 0 );
11162 m_width = newWidth;
11163 return *this;
11164 }
11165 Column&& width( size_t newWidth ) && {
11166 assert( newWidth > 0 );
11167 m_width = newWidth;
11168 return CATCH_MOVE( *this );
11169 }
11170 Column& indent( size_t newIndent ) & {
11171 m_indent = newIndent;
11172 return *this;
11173 }
11174 Column&& indent( size_t newIndent ) && {
11175 m_indent = newIndent;
11176 return CATCH_MOVE( *this );
11177 }
11178 Column& initialIndent( size_t newIndent ) & {
11179 m_initialIndent = newIndent;
11180 return *this;
11181 }
11182 Column&& initialIndent( size_t newIndent ) && {
11183 m_initialIndent = newIndent;
11184 return CATCH_MOVE( *this );
11185 }
11186
11187 size_t width() const { return m_width; }
11188 const_iterator begin() const { return const_iterator( *this ); }
11189 const_iterator end() const {
11190 return { *this, const_iterator::EndTag{} };
11191 }
11192
11193 friend std::ostream& operator<<( std::ostream& os,
11194 Column const& col );
11195
11196 friend Columns operator+( Column const& lhs, Column const& rhs );
11197 friend Columns operator+( Column&& lhs, Column&& rhs );
11198 };
11199
11200 //! Creates a column that serves as an empty space of specific width
11201 Column Spacer( size_t spaceWidth );
11202
11203 class Columns {
11204 std::vector<Column> m_columns;
11205
11206 public:
11207 class iterator {
11208 friend Columns;
11209 struct EndTag {};
11210
11211 std::vector<Column> const& m_columns;
11212 std::vector<Column::const_iterator> m_iterators;
11213 size_t m_activeIterators;
11214
11215 iterator( Columns const& columns, EndTag );
11216
11217 public:
11218 using difference_type = std::ptrdiff_t;
11219 using value_type = std::string;
11220 using pointer = value_type*;
11221 using reference = value_type&;
11222 using iterator_category = std::forward_iterator_tag;
11223
11224 explicit iterator( Columns const& columns );
11225
11226 auto operator==( iterator const& other ) const -> bool {
11227 return m_iterators == other.m_iterators;
11228 }
11229 auto operator!=( iterator const& other ) const -> bool {
11230 return m_iterators != other.m_iterators;
11231 }
11232 std::string operator*() const;
11233 iterator& operator++();
11234 iterator operator++( int );
11235 };
11236 using const_iterator = iterator;
11237
11238 iterator begin() const { return iterator( *this ); }
11239 iterator end() const { return { *this, iterator::EndTag() }; }
11240
11241 friend Columns& operator+=( Columns& lhs, Column const& rhs );
11242 friend Columns& operator+=( Columns& lhs, Column&& rhs );
11243 friend Columns operator+( Columns const& lhs, Column const& rhs );
11244 friend Columns operator+( Columns&& lhs, Column&& rhs );
11245
11246 friend std::ostream& operator<<( std::ostream& os,
11247 Columns const& cols );
11248 };
11249
11250 } // namespace TextFlow
11251} // namespace Catch
11252#endif // CATCH_TEXTFLOW_HPP_INCLUDED
11253
11254
11255#ifndef CATCH_TO_STRING_HPP_INCLUDED
11256#define CATCH_TO_STRING_HPP_INCLUDED
11257
11258#include <string>
11259
11260
11261namespace Catch {
11262 template <typename T>
11263 std::string to_string(T const& t) {
11264#if defined(CATCH_CONFIG_CPP11_TO_STRING)
11265 return std::to_string(t);
11266#else
11267 ReusableStringStream rss;
11268 rss << t;
11269 return rss.str();
11270#endif
11271 }
11272} // end namespace Catch
11273
11274#endif // CATCH_TO_STRING_HPP_INCLUDED
11275
11276
11277#ifndef CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
11278#define CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
11279
11280namespace Catch {
11281 bool uncaught_exceptions();
11282} // end namespace Catch
11283
11284#endif // CATCH_UNCAUGHT_EXCEPTIONS_HPP_INCLUDED
11285
11286
11287#ifndef CATCH_XMLWRITER_HPP_INCLUDED
11288#define CATCH_XMLWRITER_HPP_INCLUDED
11289
11290
11291#include <iosfwd>
11292#include <vector>
11293#include <cstdint>
11294
11295namespace Catch {
11296 enum class XmlFormatting : std::uint8_t {
11297 None = 0x00,
11298 Indent = 0x01,
11299 Newline = 0x02,
11300 };
11301
11302 constexpr XmlFormatting operator|( XmlFormatting lhs, XmlFormatting rhs ) {
11303 return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) |
11304 static_cast<std::uint8_t>( rhs ) );
11305 }
11306
11307 constexpr XmlFormatting operator&( XmlFormatting lhs, XmlFormatting rhs ) {
11308 return static_cast<XmlFormatting>( static_cast<std::uint8_t>( lhs ) &
11309 static_cast<std::uint8_t>( rhs ) );
11310 }
11311
11312
11313 /**
11314 * Helper for XML-encoding text (escaping angle brackets, quotes, etc)
11315 *
11316 * Note: doesn't take ownership of passed strings, and thus the
11317 * encoded string must outlive the encoding instance.
11318 */
11319 class XmlEncode {
11320 public:
11321 enum ForWhat { ForTextNodes, ForAttributes };
11322
11323 constexpr XmlEncode( StringRef str, ForWhat forWhat = ForTextNodes ):
11324 m_str( str ), m_forWhat( forWhat ) {}
11325
11326
11327 void encodeTo( std::ostream& os ) const;
11328
11329 friend std::ostream& operator << ( std::ostream& os, XmlEncode const& xmlEncode );
11330
11331 private:
11332 StringRef m_str;
11333 ForWhat m_forWhat;
11334 };
11335
11336 class XmlWriter {
11337 public:
11338
11339 class ScopedElement {
11340 public:
11341 ScopedElement( XmlWriter* writer, XmlFormatting fmt );
11342
11343 ScopedElement( ScopedElement&& other ) noexcept;
11344 ScopedElement& operator=( ScopedElement&& other ) noexcept;
11345
11346 ~ScopedElement();
11347
11348 ScopedElement&
11349 writeText( StringRef text,
11350 XmlFormatting fmt = XmlFormatting::Newline |
11351 XmlFormatting::Indent );
11352
11353 ScopedElement& writeAttribute( StringRef name,
11354 StringRef attribute );
11355 template <typename T,
11356 // Without this SFINAE, this overload is a better match
11357 // for `std::string`, `char const*`, `char const[N]` args.
11358 // While it would still work, it would cause code bloat
11359 // and multiple iteration over the strings
11360 typename = typename std::enable_if_t<
11361 !std::is_convertible<T, StringRef>::value>>
11362 ScopedElement& writeAttribute( StringRef name,
11363 T const& attribute ) {
11364 m_writer->writeAttribute( name, attribute );
11365 return *this;
11366 }
11367
11368 private:
11369 XmlWriter* m_writer = nullptr;
11370 XmlFormatting m_fmt;
11371 };
11372
11373 XmlWriter( std::ostream& os );
11374 ~XmlWriter();
11375
11376 XmlWriter( XmlWriter const& ) = delete;
11377 XmlWriter& operator=( XmlWriter const& ) = delete;
11378
11379 XmlWriter& startElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
11380
11381 ScopedElement scopedElement( std::string const& name, XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
11382
11383 XmlWriter& endElement(XmlFormatting fmt = XmlFormatting::Newline | XmlFormatting::Indent);
11384
11385 //! The attribute content is XML-encoded
11386 XmlWriter& writeAttribute( StringRef name, StringRef attribute );
11387
11388 //! Writes the attribute as "true/false"
11389 XmlWriter& writeAttribute( StringRef name, bool attribute );
11390
11391 //! The attribute content is XML-encoded
11392 XmlWriter& writeAttribute( StringRef name, char const* attribute );
11393
11394 //! The attribute value must provide op<<(ostream&, T). The resulting
11395 //! serialization is XML-encoded
11396 template <typename T,
11397 // Without this SFINAE, this overload is a better match
11398 // for `std::string`, `char const*`, `char const[N]` args.
11399 // While it would still work, it would cause code bloat
11400 // and multiple iteration over the strings
11401 typename = typename std::enable_if_t<
11402 !std::is_convertible<T, StringRef>::value>>
11403 XmlWriter& writeAttribute( StringRef name, T const& attribute ) {
11404 ReusableStringStream rss;
11405 rss << attribute;
11406 return writeAttribute( name, rss.str() );
11407 }
11408
11409 //! Writes escaped `text` in a element
11410 XmlWriter& writeText( StringRef text,
11411 XmlFormatting fmt = XmlFormatting::Newline |
11412 XmlFormatting::Indent );
11413
11414 //! Writes XML comment as "<!-- text -->"
11415 XmlWriter& writeComment( StringRef text,
11416 XmlFormatting fmt = XmlFormatting::Newline |
11417 XmlFormatting::Indent );
11418
11419 void writeStylesheetRef( StringRef url );
11420
11421 void ensureTagClosed();
11422
11423 private:
11424
11425 void applyFormatting(XmlFormatting fmt);
11426
11427 void writeDeclaration();
11428
11429 void newlineIfNecessary();
11430
11431 bool m_tagIsOpen = false;
11432 bool m_needsNewline = false;
11433 std::vector<std::string> m_tags;
11434 std::string m_indent;
11435 std::ostream& m_os;
11436 };
11437
11438}
11439
11440#endif // CATCH_XMLWRITER_HPP_INCLUDED
11441
11442
11443/** \file
11444 * This is a convenience header for Catch2's Matcher support. It includes
11445 * **all** of Catch2 headers related to matchers.
11446 *
11447 * Generally the Catch2 users should use specific includes they need,
11448 * but this header can be used instead for ease-of-experimentation, or
11449 * just plain convenience, at the cost of increased compilation times.
11450 *
11451 * When a new header is added to either the `matchers` folder, or to
11452 * the corresponding internal subfolder, it should be added here.
11453 */
11454
11455#ifndef CATCH_MATCHERS_ALL_HPP_INCLUDED
11456#define CATCH_MATCHERS_ALL_HPP_INCLUDED
11457
11458
11459
11460#ifndef CATCH_MATCHERS_HPP_INCLUDED
11461#define CATCH_MATCHERS_HPP_INCLUDED
11462
11463
11464
11465#ifndef CATCH_MATCHERS_IMPL_HPP_INCLUDED
11466#define CATCH_MATCHERS_IMPL_HPP_INCLUDED
11467
11468
11469#include <string>
11470
11471namespace Catch {
11472
11473#ifdef __clang__
11474# pragma clang diagnostic push
11475# pragma clang diagnostic ignored "-Wsign-compare"
11476# pragma clang diagnostic ignored "-Wnon-virtual-dtor"
11477#elif defined __GNUC__
11478# pragma GCC diagnostic push
11479# pragma GCC diagnostic ignored "-Wsign-compare"
11480# pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
11481#endif
11482
11483 template<typename ArgT, typename MatcherT>
11484 class MatchExpr : public ITransientExpression {
11485 ArgT && m_arg;
11486 MatcherT const& m_matcher;
11487 public:
11488 constexpr MatchExpr( ArgT && arg, MatcherT const& matcher )
11489 : ITransientExpression{ true, matcher.match( arg ) }, // not forwarding arg here on purpose
11490 m_arg( CATCH_FORWARD(arg) ),
11491 m_matcher( matcher )
11492 {}
11493
11494 void streamReconstructedExpression( std::ostream& os ) const override {
11495 os << Catch::Detail::stringify( m_arg )
11496 << ' '
11497 << m_matcher.toString();
11498 }
11499 };
11500
11501#ifdef __clang__
11502# pragma clang diagnostic pop
11503#elif defined __GNUC__
11504# pragma GCC diagnostic pop
11505#endif
11506
11507
11508 namespace Matchers {
11509 template <typename ArgT>
11510 class MatcherBase;
11511 }
11512
11513 using StringMatcher = Matchers::MatcherBase<std::string>;
11514
11515 void handleExceptionMatchExpr( AssertionHandler& handler, StringMatcher const& matcher );
11516
11517 template<typename ArgT, typename MatcherT>
11518 constexpr MatchExpr<ArgT, MatcherT>
11519 makeMatchExpr( ArgT&& arg, MatcherT const& matcher ) {
11520 return MatchExpr<ArgT, MatcherT>( CATCH_FORWARD(arg), matcher );
11521 }
11522
11523} // namespace Catch
11524
11525
11526///////////////////////////////////////////////////////////////////////////////
11527#define INTERNAL_CHECK_THAT( macroName, matcher, resultDisposition, arg ) \
11528 do { \
11529 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(arg) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
11530 INTERNAL_CATCH_TRY { \
11531 catchAssertionHandler.handleExpr( Catch::makeMatchExpr( arg, matcher ) ); \
11532 } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \
11533 catchAssertionHandler.complete(); \
11534 } while( false )
11535
11536
11537///////////////////////////////////////////////////////////////////////////////
11538#define INTERNAL_CATCH_THROWS_MATCHES( macroName, exceptionType, resultDisposition, matcher, ... ) \
11539 do { \
11540 Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__) ", " CATCH_INTERNAL_STRINGIFY(exceptionType) ", " CATCH_INTERNAL_STRINGIFY(matcher), resultDisposition ); \
11541 if( catchAssertionHandler.allowThrows() ) \
11542 try { \
11543 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
11544 CATCH_INTERNAL_SUPPRESS_USELESS_CAST_WARNINGS \
11545 static_cast<void>(__VA_ARGS__ ); \
11546 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \
11547 catchAssertionHandler.handleUnexpectedExceptionNotThrown(); \
11548 } \
11549 catch( exceptionType const& ex ) { \
11550 catchAssertionHandler.handleExpr( Catch::makeMatchExpr( ex, matcher ) ); \
11551 } \
11552 catch( ... ) { \
11553 catchAssertionHandler.handleUnexpectedInflightException(); \
11554 } \
11555 else \
11556 catchAssertionHandler.handleThrowingCallSkipped(); \
11557 catchAssertionHandler.complete(); \
11558 } while( false )
11559
11560
11561#endif // CATCH_MATCHERS_IMPL_HPP_INCLUDED
11562
11563#include <string>
11564#include <vector>
11565
11566namespace Catch {
11567namespace Matchers {
11568
11569 class MatcherUntypedBase {
11570 public:
11571 MatcherUntypedBase() = default;
11572
11573 MatcherUntypedBase(MatcherUntypedBase const&) = default;
11574 MatcherUntypedBase(MatcherUntypedBase&&) = default;
11575
11576 MatcherUntypedBase& operator = (MatcherUntypedBase const&) = delete;
11577 MatcherUntypedBase& operator = (MatcherUntypedBase&&) = delete;
11578
11579 std::string toString() const;
11580
11581 protected:
11582 virtual ~MatcherUntypedBase(); // = default;
11583 virtual std::string describe() const = 0;
11584 mutable std::string m_cachedToString;
11585 };
11586
11587
11588 template<typename T>
11589 class MatcherBase : public MatcherUntypedBase {
11590 public:
11591 virtual bool match( T const& arg ) const = 0;
11592 };
11593
11594 namespace Detail {
11595
11596 template<typename ArgT>
11597 class MatchAllOf final : public MatcherBase<ArgT> {
11598 std::vector<MatcherBase<ArgT> const*> m_matchers;
11599
11600 public:
11601 MatchAllOf() = default;
11602 MatchAllOf(MatchAllOf const&) = delete;
11603 MatchAllOf& operator=(MatchAllOf const&) = delete;
11604 MatchAllOf(MatchAllOf&&) = default;
11605 MatchAllOf& operator=(MatchAllOf&&) = default;
11606
11607
11608 bool match( ArgT const& arg ) const override {
11609 for( auto matcher : m_matchers ) {
11610 if (!matcher->match(arg))
11611 return false;
11612 }
11613 return true;
11614 }
11615 std::string describe() const override {
11616 std::string description;
11617 description.reserve( 4 + m_matchers.size()*32 );
11618 description += "( ";
11619 bool first = true;
11620 for( auto matcher : m_matchers ) {
11621 if( first )
11622 first = false;
11623 else
11624 description += " and ";
11625 description += matcher->toString();
11626 }
11627 description += " )";
11628 return description;
11629 }
11630
11631 friend MatchAllOf operator&& (MatchAllOf&& lhs, MatcherBase<ArgT> const& rhs) {
11632 lhs.m_matchers.push_back(&rhs);
11633 return CATCH_MOVE(lhs);
11634 }
11635 friend MatchAllOf operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf&& rhs) {
11636 rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
11637 return CATCH_MOVE(rhs);
11638 }
11639 };
11640
11641 //! lvalue overload is intentionally deleted, users should
11642 //! not be trying to compose stored composition matchers
11643 template<typename ArgT>
11644 MatchAllOf<ArgT> operator&& (MatchAllOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
11645 //! lvalue overload is intentionally deleted, users should
11646 //! not be trying to compose stored composition matchers
11647 template<typename ArgT>
11648 MatchAllOf<ArgT> operator&& (MatcherBase<ArgT> const& lhs, MatchAllOf<ArgT> const& rhs) = delete;
11649
11650 template<typename ArgT>
11651 class MatchAnyOf final : public MatcherBase<ArgT> {
11652 std::vector<MatcherBase<ArgT> const*> m_matchers;
11653 public:
11654 MatchAnyOf() = default;
11655 MatchAnyOf(MatchAnyOf const&) = delete;
11656 MatchAnyOf& operator=(MatchAnyOf const&) = delete;
11657 MatchAnyOf(MatchAnyOf&&) = default;
11658 MatchAnyOf& operator=(MatchAnyOf&&) = default;
11659
11660 bool match( ArgT const& arg ) const override {
11661 for( auto matcher : m_matchers ) {
11662 if (matcher->match(arg))
11663 return true;
11664 }
11665 return false;
11666 }
11667 std::string describe() const override {
11668 std::string description;
11669 description.reserve( 4 + m_matchers.size()*32 );
11670 description += "( ";
11671 bool first = true;
11672 for( auto matcher : m_matchers ) {
11673 if( first )
11674 first = false;
11675 else
11676 description += " or ";
11677 description += matcher->toString();
11678 }
11679 description += " )";
11680 return description;
11681 }
11682
11683 friend MatchAnyOf operator|| (MatchAnyOf&& lhs, MatcherBase<ArgT> const& rhs) {
11684 lhs.m_matchers.push_back(&rhs);
11685 return CATCH_MOVE(lhs);
11686 }
11687 friend MatchAnyOf operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf&& rhs) {
11688 rhs.m_matchers.insert(rhs.m_matchers.begin(), &lhs);
11689 return CATCH_MOVE(rhs);
11690 }
11691 };
11692
11693 //! lvalue overload is intentionally deleted, users should
11694 //! not be trying to compose stored composition matchers
11695 template<typename ArgT>
11696 MatchAnyOf<ArgT> operator|| (MatchAnyOf<ArgT> const& lhs, MatcherBase<ArgT> const& rhs) = delete;
11697 //! lvalue overload is intentionally deleted, users should
11698 //! not be trying to compose stored composition matchers
11699 template<typename ArgT>
11700 MatchAnyOf<ArgT> operator|| (MatcherBase<ArgT> const& lhs, MatchAnyOf<ArgT> const& rhs) = delete;
11701
11702 template<typename ArgT>
11703 class MatchNotOf final : public MatcherBase<ArgT> {
11704 MatcherBase<ArgT> const& m_underlyingMatcher;
11705
11706 public:
11707 explicit MatchNotOf( MatcherBase<ArgT> const& underlyingMatcher ):
11708 m_underlyingMatcher( underlyingMatcher )
11709 {}
11710
11711 bool match( ArgT const& arg ) const override {
11712 return !m_underlyingMatcher.match( arg );
11713 }
11714
11715 std::string describe() const override {
11716 return "not " + m_underlyingMatcher.toString();
11717 }
11718 };
11719
11720 } // namespace Detail
11721
11722 template <typename T>
11723 Detail::MatchAllOf<T> operator&& (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
11724 return Detail::MatchAllOf<T>{} && lhs && rhs;
11725 }
11726 template <typename T>
11727 Detail::MatchAnyOf<T> operator|| (MatcherBase<T> const& lhs, MatcherBase<T> const& rhs) {
11728 return Detail::MatchAnyOf<T>{} || lhs || rhs;
11729 }
11730
11731 template <typename T>
11732 Detail::MatchNotOf<T> operator! (MatcherBase<T> const& matcher) {
11733 return Detail::MatchNotOf<T>{ matcher };
11734 }
11735
11736
11737} // namespace Matchers
11738} // namespace Catch
11739
11740
11741#if defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
11742 #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
11743 #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
11744
11745 #define CATCH_CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CATCH_CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
11746 #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CATCH_CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
11747
11748 #define CATCH_CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
11749 #define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CATCH_REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
11750
11751#elif defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
11752
11753 #define CATCH_REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
11754 #define CATCH_REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
11755
11756 #define CATCH_CHECK_THROWS_WITH( expr, matcher ) (void)(0)
11757 #define CATCH_CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
11758
11759 #define CATCH_CHECK_THAT( arg, matcher ) (void)(0)
11760 #define CATCH_REQUIRE_THAT( arg, matcher ) (void)(0)
11761
11762#elif !defined(CATCH_CONFIG_PREFIX_ALL) && !defined(CATCH_CONFIG_DISABLE)
11763
11764 #define REQUIRE_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "REQUIRE_THROWS_WITH", Catch::ResultDisposition::Normal, matcher, expr )
11765 #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "REQUIRE_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::Normal, matcher, expr )
11766
11767 #define CHECK_THROWS_WITH( expr, matcher ) INTERNAL_CATCH_THROWS_STR_MATCHES( "CHECK_THROWS_WITH", Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
11768 #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) INTERNAL_CATCH_THROWS_MATCHES( "CHECK_THROWS_MATCHES", exceptionType, Catch::ResultDisposition::ContinueOnFailure, matcher, expr )
11769
11770 #define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "CHECK_THAT", matcher, Catch::ResultDisposition::ContinueOnFailure, arg )
11771 #define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( "REQUIRE_THAT", matcher, Catch::ResultDisposition::Normal, arg )
11772
11773#elif !defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CONFIG_DISABLE)
11774
11775 #define REQUIRE_THROWS_WITH( expr, matcher ) (void)(0)
11776 #define REQUIRE_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
11777
11778 #define CHECK_THROWS_WITH( expr, matcher ) (void)(0)
11779 #define CHECK_THROWS_MATCHES( expr, exceptionType, matcher ) (void)(0)
11780
11781 #define CHECK_THAT( arg, matcher ) (void)(0)
11782 #define REQUIRE_THAT( arg, matcher ) (void)(0)
11783
11784#endif // end of user facing macro declarations
11785
11786#endif // CATCH_MATCHERS_HPP_INCLUDED
11787
11788
11789#ifndef CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
11790#define CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
11791
11792
11793
11794#ifndef CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
11795#define CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
11796
11797
11798#include <array>
11799#include <algorithm>
11800#include <string>
11801#include <type_traits>
11802
11803namespace Catch {
11804namespace Matchers {
11805 class MatcherGenericBase : public MatcherUntypedBase {
11806 public:
11807 MatcherGenericBase() = default;
11808 ~MatcherGenericBase() override; // = default;
11809
11810 MatcherGenericBase(MatcherGenericBase const&) = default;
11811 MatcherGenericBase(MatcherGenericBase&&) = default;
11812
11813 MatcherGenericBase& operator=(MatcherGenericBase const&) = delete;
11814 MatcherGenericBase& operator=(MatcherGenericBase&&) = delete;
11815 };
11816
11817
11818 namespace Detail {
11819 template<std::size_t N, std::size_t M>
11820 std::array<void const*, N + M> array_cat(std::array<void const*, N> && lhs, std::array<void const*, M> && rhs) {
11821 std::array<void const*, N + M> arr{};
11822 std::copy_n(lhs.begin(), N, arr.begin());
11823 std::copy_n(rhs.begin(), M, arr.begin() + N);
11824 return arr;
11825 }
11826
11827 template<std::size_t N>
11828 std::array<void const*, N+1> array_cat(std::array<void const*, N> && lhs, void const* rhs) {
11829 std::array<void const*, N+1> arr{};
11830 std::copy_n(lhs.begin(), N, arr.begin());
11831 arr[N] = rhs;
11832 return arr;
11833 }
11834
11835 template<std::size_t N>
11836 std::array<void const*, N+1> array_cat(void const* lhs, std::array<void const*, N> && rhs) {
11837 std::array<void const*, N + 1> arr{ {lhs} };
11838 std::copy_n(rhs.begin(), N, arr.begin() + 1);
11839 return arr;
11840 }
11841
11842 template<typename T>
11843 using is_generic_matcher = std::is_base_of<
11844 Catch::Matchers::MatcherGenericBase,
11845 std::remove_cv_t<std::remove_reference_t<T>>
11846 >;
11847
11848 template<typename... Ts>
11849 using are_generic_matchers = Catch::Detail::conjunction<is_generic_matcher<Ts>...>;
11850
11851 template<typename T>
11852 using is_matcher = std::is_base_of<
11853 Catch::Matchers::MatcherUntypedBase,
11854 std::remove_cv_t<std::remove_reference_t<T>>
11855 >;
11856
11857
11858 template<std::size_t N, typename Arg>
11859 bool match_all_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
11860 return true;
11861 }
11862
11863 template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
11864 bool match_all_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
11865 return static_cast<T const*>(matchers[Idx])->match(arg) && match_all_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
11866 }
11867
11868
11869 template<std::size_t N, typename Arg>
11870 bool match_any_of(Arg&&, std::array<void const*, N> const&, std::index_sequence<>) {
11871 return false;
11872 }
11873
11874 template<typename T, typename... MatcherTs, std::size_t N, typename Arg, std::size_t Idx, std::size_t... Indices>
11875 bool match_any_of(Arg&& arg, std::array<void const*, N> const& matchers, std::index_sequence<Idx, Indices...>) {
11876 return static_cast<T const*>(matchers[Idx])->match(arg) || match_any_of<MatcherTs...>(arg, matchers, std::index_sequence<Indices...>{});
11877 }
11878
11879 std::string describe_multi_matcher(StringRef combine, std::string const* descriptions_begin, std::string const* descriptions_end);
11880
11881 template<typename... MatcherTs, std::size_t... Idx>
11882 std::string describe_multi_matcher(StringRef combine, std::array<void const*, sizeof...(MatcherTs)> const& matchers, std::index_sequence<Idx...>) {
11883 std::array<std::string, sizeof...(MatcherTs)> descriptions {{
11884 static_cast<MatcherTs const*>(matchers[Idx])->toString()...
11885 }};
11886
11887 return describe_multi_matcher(combine, descriptions.data(), descriptions.data() + descriptions.size());
11888 }
11889
11890
11891 template<typename... MatcherTs>
11892 class MatchAllOfGeneric final : public MatcherGenericBase {
11893 public:
11894 MatchAllOfGeneric(MatchAllOfGeneric const&) = delete;
11895 MatchAllOfGeneric& operator=(MatchAllOfGeneric const&) = delete;
11896 MatchAllOfGeneric(MatchAllOfGeneric&&) = default;
11897 MatchAllOfGeneric& operator=(MatchAllOfGeneric&&) = default;
11898
11899 MatchAllOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
11900 explicit MatchAllOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
11901
11902 template<typename Arg>
11903 bool match(Arg&& arg) const {
11904 return match_all_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
11905 }
11906
11907 std::string describe() const override {
11908 return describe_multi_matcher<MatcherTs...>(" and "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
11909 }
11910
11911 // Has to be public to enable the concatenating operators
11912 // below, because they are not friend of the RHS, only LHS,
11913 // and thus cannot access private fields of RHS
11914 std::array<void const*, sizeof...( MatcherTs )> m_matchers;
11915
11916
11917 //! Avoids type nesting for `GenericAllOf && GenericAllOf` case
11918 template<typename... MatchersRHS>
11919 friend
11920 MatchAllOfGeneric<MatcherTs..., MatchersRHS...> operator && (
11921 MatchAllOfGeneric<MatcherTs...>&& lhs,
11922 MatchAllOfGeneric<MatchersRHS...>&& rhs) {
11923 return MatchAllOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
11924 }
11925
11926 //! Avoids type nesting for `GenericAllOf && some matcher` case
11927 template<typename MatcherRHS>
11928 friend std::enable_if_t<is_matcher<MatcherRHS>::value,
11929 MatchAllOfGeneric<MatcherTs..., MatcherRHS>> operator && (
11930 MatchAllOfGeneric<MatcherTs...>&& lhs,
11931 MatcherRHS const& rhs) {
11932 return MatchAllOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(&rhs))};
11933 }
11934
11935 //! Avoids type nesting for `some matcher && GenericAllOf` case
11936 template<typename MatcherLHS>
11937 friend std::enable_if_t<is_matcher<MatcherLHS>::value,
11938 MatchAllOfGeneric<MatcherLHS, MatcherTs...>> operator && (
11939 MatcherLHS const& lhs,
11940 MatchAllOfGeneric<MatcherTs...>&& rhs) {
11941 return MatchAllOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
11942 }
11943 };
11944
11945
11946 template<typename... MatcherTs>
11947 class MatchAnyOfGeneric final : public MatcherGenericBase {
11948 public:
11949 MatchAnyOfGeneric(MatchAnyOfGeneric const&) = delete;
11950 MatchAnyOfGeneric& operator=(MatchAnyOfGeneric const&) = delete;
11951 MatchAnyOfGeneric(MatchAnyOfGeneric&&) = default;
11952 MatchAnyOfGeneric& operator=(MatchAnyOfGeneric&&) = default;
11953
11954 MatchAnyOfGeneric(MatcherTs const&... matchers) : m_matchers{ {std::addressof(matchers)...} } {}
11955 explicit MatchAnyOfGeneric(std::array<void const*, sizeof...(MatcherTs)> matchers) : m_matchers{matchers} {}
11956
11957 template<typename Arg>
11958 bool match(Arg&& arg) const {
11959 return match_any_of<MatcherTs...>(arg, m_matchers, std::index_sequence_for<MatcherTs...>{});
11960 }
11961
11962 std::string describe() const override {
11963 return describe_multi_matcher<MatcherTs...>(" or "_sr, m_matchers, std::index_sequence_for<MatcherTs...>{});
11964 }
11965
11966
11967 // Has to be public to enable the concatenating operators
11968 // below, because they are not friend of the RHS, only LHS,
11969 // and thus cannot access private fields of RHS
11970 std::array<void const*, sizeof...( MatcherTs )> m_matchers;
11971
11972 //! Avoids type nesting for `GenericAnyOf || GenericAnyOf` case
11973 template<typename... MatchersRHS>
11974 friend MatchAnyOfGeneric<MatcherTs..., MatchersRHS...> operator || (
11975 MatchAnyOfGeneric<MatcherTs...>&& lhs,
11976 MatchAnyOfGeneric<MatchersRHS...>&& rhs) {
11977 return MatchAnyOfGeneric<MatcherTs..., MatchersRHS...>{array_cat(CATCH_MOVE(lhs.m_matchers), CATCH_MOVE(rhs.m_matchers))};
11978 }
11979
11980 //! Avoids type nesting for `GenericAnyOf || some matcher` case
11981 template<typename MatcherRHS>
11982 friend std::enable_if_t<is_matcher<MatcherRHS>::value,
11983 MatchAnyOfGeneric<MatcherTs..., MatcherRHS>> operator || (
11984 MatchAnyOfGeneric<MatcherTs...>&& lhs,
11985 MatcherRHS const& rhs) {
11986 return MatchAnyOfGeneric<MatcherTs..., MatcherRHS>{array_cat(CATCH_MOVE(lhs.m_matchers), static_cast<void const*>(std::addressof(rhs)))};
11987 }
11988
11989 //! Avoids type nesting for `some matcher || GenericAnyOf` case
11990 template<typename MatcherLHS>
11991 friend std::enable_if_t<is_matcher<MatcherLHS>::value,
11992 MatchAnyOfGeneric<MatcherLHS, MatcherTs...>> operator || (
11993 MatcherLHS const& lhs,
11994 MatchAnyOfGeneric<MatcherTs...>&& rhs) {
11995 return MatchAnyOfGeneric<MatcherLHS, MatcherTs...>{array_cat(static_cast<void const*>(std::addressof(lhs)), CATCH_MOVE(rhs.m_matchers))};
11996 }
11997 };
11998
11999
12000 template<typename MatcherT>
12001 class MatchNotOfGeneric final : public MatcherGenericBase {
12002 MatcherT const& m_matcher;
12003
12004 public:
12005 MatchNotOfGeneric(MatchNotOfGeneric const&) = delete;
12006 MatchNotOfGeneric& operator=(MatchNotOfGeneric const&) = delete;
12007 MatchNotOfGeneric(MatchNotOfGeneric&&) = default;
12008 MatchNotOfGeneric& operator=(MatchNotOfGeneric&&) = default;
12009
12010 explicit MatchNotOfGeneric(MatcherT const& matcher) : m_matcher{matcher} {}
12011
12012 template<typename Arg>
12013 bool match(Arg&& arg) const {
12014 return !m_matcher.match(arg);
12015 }
12016
12017 std::string describe() const override {
12018 return "not " + m_matcher.toString();
12019 }
12020
12021 //! Negating negation can just unwrap and return underlying matcher
12022 friend MatcherT const& operator ! (MatchNotOfGeneric<MatcherT> const& matcher) {
12023 return matcher.m_matcher;
12024 }
12025 };
12026 } // namespace Detail
12027
12028
12029 // compose only generic matchers
12030 template<typename MatcherLHS, typename MatcherRHS>
12031 std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherRHS>>
12032 operator && (MatcherLHS const& lhs, MatcherRHS const& rhs) {
12033 return { lhs, rhs };
12034 }
12035
12036 template<typename MatcherLHS, typename MatcherRHS>
12037 std::enable_if_t<Detail::are_generic_matchers<MatcherLHS, MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherRHS>>
12038 operator || (MatcherLHS const& lhs, MatcherRHS const& rhs) {
12039 return { lhs, rhs };
12040 }
12041
12042 //! Wrap provided generic matcher in generic negator
12043 template<typename MatcherT>
12044 std::enable_if_t<Detail::is_generic_matcher<MatcherT>::value, Detail::MatchNotOfGeneric<MatcherT>>
12045 operator ! (MatcherT const& matcher) {
12046 return Detail::MatchNotOfGeneric<MatcherT>{matcher};
12047 }
12048
12049
12050 // compose mixed generic and non-generic matchers
12051 template<typename MatcherLHS, typename ArgRHS>
12052 std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAllOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
12053 operator && (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
12054 return { lhs, rhs };
12055 }
12056
12057 template<typename ArgLHS, typename MatcherRHS>
12058 std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAllOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
12059 operator && (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
12060 return { lhs, rhs };
12061 }
12062
12063 template<typename MatcherLHS, typename ArgRHS>
12064 std::enable_if_t<Detail::is_generic_matcher<MatcherLHS>::value, Detail::MatchAnyOfGeneric<MatcherLHS, MatcherBase<ArgRHS>>>
12065 operator || (MatcherLHS const& lhs, MatcherBase<ArgRHS> const& rhs) {
12066 return { lhs, rhs };
12067 }
12068
12069 template<typename ArgLHS, typename MatcherRHS>
12070 std::enable_if_t<Detail::is_generic_matcher<MatcherRHS>::value, Detail::MatchAnyOfGeneric<MatcherBase<ArgLHS>, MatcherRHS>>
12071 operator || (MatcherBase<ArgLHS> const& lhs, MatcherRHS const& rhs) {
12072 return { lhs, rhs };
12073 }
12074
12075} // namespace Matchers
12076} // namespace Catch
12077
12078#endif // CATCH_MATCHERS_TEMPLATED_HPP_INCLUDED
12079
12080namespace Catch {
12081 namespace Matchers {
12082
12083 class IsEmptyMatcher final : public MatcherGenericBase {
12084 public:
12085 template <typename RangeLike>
12086 bool match(RangeLike&& rng) const {
12087#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
12088 using Catch::Detail::empty;
12089#else
12090 using std::empty;
12091#endif
12092 return empty(rng);
12093 }
12094
12095 std::string describe() const override;
12096 };
12097
12098 class HasSizeMatcher final : public MatcherGenericBase {
12099 std::size_t m_target_size;
12100 public:
12101 explicit HasSizeMatcher(std::size_t target_size):
12102 m_target_size(target_size)
12103 {}
12104
12105 template <typename RangeLike>
12106 bool match(RangeLike&& rng) const {
12107#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
12108 using Catch::Detail::size;
12109#else
12110 using std::size;
12111#endif
12112 return size(rng) == m_target_size;
12113 }
12114
12115 std::string describe() const override;
12116 };
12117
12118 template <typename Matcher>
12119 class SizeMatchesMatcher final : public MatcherGenericBase {
12120 Matcher m_matcher;
12121 public:
12122 explicit SizeMatchesMatcher(Matcher m):
12123 m_matcher(CATCH_MOVE(m))
12124 {}
12125
12126 template <typename RangeLike>
12127 bool match(RangeLike&& rng) const {
12128#if defined(CATCH_CONFIG_POLYFILL_NONMEMBER_CONTAINER_ACCESS)
12129 using Catch::Detail::size;
12130#else
12131 using std::size;
12132#endif
12133 return m_matcher.match(size(rng));
12134 }
12135
12136 std::string describe() const override {
12137 return "size matches " + m_matcher.describe();
12138 }
12139 };
12140
12141
12142 //! Creates a matcher that accepts empty ranges/containers
12143 IsEmptyMatcher IsEmpty();
12144 //! Creates a matcher that accepts ranges/containers with specific size
12145 HasSizeMatcher SizeIs(std::size_t sz);
12146 template <typename Matcher>
12147 std::enable_if_t<Detail::is_matcher<Matcher>::value,
12148 SizeMatchesMatcher<Matcher>> SizeIs(Matcher&& m) {
12149 return SizeMatchesMatcher<Matcher>{CATCH_FORWARD(m)};
12150 }
12151
12152 } // end namespace Matchers
12153} // end namespace Catch
12154
12155#endif // CATCH_MATCHERS_CONTAINER_PROPERTIES_HPP_INCLUDED
12156
12157
12158#ifndef CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
12159#define CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
12160
12161
12162#include <algorithm>
12163#include <functional>
12164
12165namespace Catch {
12166 namespace Matchers {
12167 //! Matcher for checking that an element in range is equal to specific element
12168 template <typename T, typename Equality>
12169 class ContainsElementMatcher final : public MatcherGenericBase {
12170 T m_desired;
12171 Equality m_eq;
12172 public:
12173 template <typename T2, typename Equality2>
12174 ContainsElementMatcher(T2&& target, Equality2&& predicate):
12175 m_desired(CATCH_FORWARD(target)),
12176 m_eq(CATCH_FORWARD(predicate))
12177 {}
12178
12179 std::string describe() const override {
12180 return "contains element " + Catch::Detail::stringify(m_desired);
12181 }
12182
12183 template <typename RangeLike>
12184 bool match( RangeLike&& rng ) const {
12185 for ( auto&& elem : rng ) {
12186 if ( m_eq( elem, m_desired ) ) { return true; }
12187 }
12188 return false;
12189 }
12190 };
12191
12192 //! Meta-matcher for checking that an element in a range matches a specific matcher
12193 template <typename Matcher>
12194 class ContainsMatcherMatcher final : public MatcherGenericBase {
12195 Matcher m_matcher;
12196 public:
12197 // Note that we do a copy+move to avoid having to SFINAE this
12198 // constructor (and also avoid some perfect forwarding failure
12199 // cases)
12200 ContainsMatcherMatcher(Matcher matcher):
12201 m_matcher(CATCH_MOVE(matcher))
12202 {}
12203
12204 template <typename RangeLike>
12205 bool match(RangeLike&& rng) const {
12206 for (auto&& elem : rng) {
12207 if (m_matcher.match(elem)) {
12208 return true;
12209 }
12210 }
12211 return false;
12212 }
12213
12214 std::string describe() const override {
12215 return "contains element matching " + m_matcher.describe();
12216 }
12217 };
12218
12219 /**
12220 * Creates a matcher that checks whether a range contains a specific element.
12221 *
12222 * Uses `std::equal_to` to do the comparison
12223 */
12224 template <typename T>
12225 std::enable_if_t<!Detail::is_matcher<T>::value,
12226 ContainsElementMatcher<T, std::equal_to<>>> Contains(T&& elem) {
12227 return { CATCH_FORWARD(elem), std::equal_to<>{} };
12228 }
12229
12230 //! Creates a matcher that checks whether a range contains element matching a matcher
12231 template <typename Matcher>
12232 std::enable_if_t<Detail::is_matcher<Matcher>::value,
12233 ContainsMatcherMatcher<Matcher>> Contains(Matcher&& matcher) {
12234 return { CATCH_FORWARD(matcher) };
12235 }
12236
12237 /**
12238 * Creates a matcher that checks whether a range contains a specific element.
12239 *
12240 * Uses `eq` to do the comparisons, the element is provided on the rhs
12241 */
12242 template <typename T, typename Equality>
12243 ContainsElementMatcher<T, Equality> Contains(T&& elem, Equality&& eq) {
12244 return { CATCH_FORWARD(elem), CATCH_FORWARD(eq) };
12245 }
12246
12247 }
12248}
12249
12250#endif // CATCH_MATCHERS_CONTAINS_HPP_INCLUDED
12251
12252
12253#ifndef CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
12254#define CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
12255
12256
12257namespace Catch {
12258namespace Matchers {
12259
12260class ExceptionMessageMatcher final : public MatcherBase<std::exception> {
12261 std::string m_message;
12262public:
12263
12264 ExceptionMessageMatcher(std::string const& message):
12265 m_message(message)
12266 {}
12267
12268 bool match(std::exception const& ex) const override;
12269
12270 std::string describe() const override;
12271};
12272
12273//! Creates a matcher that checks whether a std derived exception has the provided message
12274ExceptionMessageMatcher Message(std::string const& message);
12275
12276template <typename StringMatcherType>
12277class ExceptionMessageMatchesMatcher final
12278 : public MatcherBase<std::exception> {
12279 StringMatcherType m_matcher;
12280
12281public:
12282 ExceptionMessageMatchesMatcher( StringMatcherType matcher ):
12283 m_matcher( CATCH_MOVE( matcher ) ) {}
12284
12285 bool match( std::exception const& ex ) const override {
12286 return m_matcher.match( ex.what() );
12287 }
12288
12289 std::string describe() const override {
12290 return " matches \"" + m_matcher.describe() + '"';
12291 }
12292};
12293
12294//! Creates a matcher that checks whether a message from an std derived
12295//! exception matches a provided matcher
12296template <typename StringMatcherType>
12297ExceptionMessageMatchesMatcher<StringMatcherType>
12298MessageMatches( StringMatcherType&& matcher ) {
12299 return { CATCH_FORWARD( matcher ) };
12300}
12301
12302} // namespace Matchers
12303} // namespace Catch
12304
12305#endif // CATCH_MATCHERS_EXCEPTION_HPP_INCLUDED
12306
12307
12308#ifndef CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
12309#define CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
12310
12311
12312namespace Catch {
12313namespace Matchers {
12314
12315 namespace Detail {
12316 enum class FloatingPointKind : uint8_t;
12317 }
12318
12319 class WithinAbsMatcher final : public MatcherBase<double> {
12320 public:
12321 WithinAbsMatcher(double target, double margin);
12322 bool match(double const& matchee) const override;
12323 std::string describe() const override;
12324 private:
12325 double m_target;
12326 double m_margin;
12327 };
12328
12329 //! Creates a matcher that accepts numbers within certain range of target
12330 WithinAbsMatcher WithinAbs( double target, double margin );
12331
12332
12333
12334 class WithinUlpsMatcher final : public MatcherBase<double> {
12335 public:
12336 WithinUlpsMatcher( double target,
12337 uint64_t ulps,
12338 Detail::FloatingPointKind baseType );
12339 bool match(double const& matchee) const override;
12340 std::string describe() const override;
12341 private:
12342 double m_target;
12343 uint64_t m_ulps;
12344 Detail::FloatingPointKind m_type;
12345 };
12346
12347 //! Creates a matcher that accepts doubles within certain ULP range of target
12348 WithinUlpsMatcher WithinULP(double target, uint64_t maxUlpDiff);
12349 //! Creates a matcher that accepts floats within certain ULP range of target
12350 WithinUlpsMatcher WithinULP(float target, uint64_t maxUlpDiff);
12351
12352
12353
12354 // Given IEEE-754 format for floats and doubles, we can assume
12355 // that float -> double promotion is lossless. Given this, we can
12356 // assume that if we do the standard relative comparison of
12357 // |lhs - rhs| <= epsilon * max(fabs(lhs), fabs(rhs)), then we get
12358 // the same result if we do this for floats, as if we do this for
12359 // doubles that were promoted from floats.
12360 class WithinRelMatcher final : public MatcherBase<double> {
12361 public:
12362 WithinRelMatcher( double target, double epsilon );
12363 bool match(double const& matchee) const override;
12364 std::string describe() const override;
12365 private:
12366 double m_target;
12367 double m_epsilon;
12368 };
12369
12370 //! Creates a matcher that accepts doubles within certain relative range of target
12371 WithinRelMatcher WithinRel(double target, double eps);
12372 //! Creates a matcher that accepts doubles within 100*DBL_EPS relative range of target
12373 WithinRelMatcher WithinRel(double target);
12374 //! Creates a matcher that accepts doubles within certain relative range of target
12375 WithinRelMatcher WithinRel(float target, float eps);
12376 //! Creates a matcher that accepts floats within 100*FLT_EPS relative range of target
12377 WithinRelMatcher WithinRel(float target);
12378
12379
12380
12381 class IsNaNMatcher final : public MatcherBase<double> {
12382 public:
12383 IsNaNMatcher() = default;
12384 bool match( double const& matchee ) const override;
12385 std::string describe() const override;
12386 };
12387
12388 IsNaNMatcher IsNaN();
12389
12390} // namespace Matchers
12391} // namespace Catch
12392
12393#endif // CATCH_MATCHERS_FLOATING_POINT_HPP_INCLUDED
12394
12395
12396#ifndef CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
12397#define CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
12398
12399
12400#include <string>
12401
12402namespace Catch {
12403namespace Matchers {
12404
12405namespace Detail {
12406 std::string finalizeDescription(const std::string& desc);
12407} // namespace Detail
12408
12409template <typename T, typename Predicate>
12410class PredicateMatcher final : public MatcherBase<T> {
12411 Predicate m_predicate;
12412 std::string m_description;
12413public:
12414
12415 PredicateMatcher(Predicate&& elem, std::string const& descr)
12416 :m_predicate(CATCH_FORWARD(elem)),
12417 m_description(Detail::finalizeDescription(descr))
12418 {}
12419
12420 bool match( T const& item ) const override {
12421 return m_predicate(item);
12422 }
12423
12424 std::string describe() const override {
12425 return m_description;
12426 }
12427};
12428
12429 /**
12430 * Creates a matcher that calls delegates `match` to the provided predicate.
12431 *
12432 * The user has to explicitly specify the argument type to the matcher
12433 */
12434 template<typename T, typename Pred>
12435 PredicateMatcher<T, Pred> Predicate(Pred&& predicate, std::string const& description = "") {
12436 static_assert(is_callable<Pred(T)>::value, "Predicate not callable with argument T");
12437 static_assert(std::is_same<bool, FunctionReturnType<Pred, T>>::value, "Predicate does not return bool");
12438 return PredicateMatcher<T, Pred>(CATCH_FORWARD(predicate), description);
12439 }
12440
12441} // namespace Matchers
12442} // namespace Catch
12443
12444#endif // CATCH_MATCHERS_PREDICATE_HPP_INCLUDED
12445
12446
12447#ifndef CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
12448#define CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
12449
12450
12451namespace Catch {
12452 namespace Matchers {
12453 // Matcher for checking that all elements in range matches a given matcher.
12454 template <typename Matcher>
12455 class AllMatchMatcher final : public MatcherGenericBase {
12456 Matcher m_matcher;
12457 public:
12458 AllMatchMatcher(Matcher matcher):
12459 m_matcher(CATCH_MOVE(matcher))
12460 {}
12461
12462 std::string describe() const override {
12463 return "all match " + m_matcher.describe();
12464 }
12465
12466 template <typename RangeLike>
12467 bool match(RangeLike&& rng) const {
12468 for (auto&& elem : rng) {
12469 if (!m_matcher.match(elem)) {
12470 return false;
12471 }
12472 }
12473 return true;
12474 }
12475 };
12476
12477 // Matcher for checking that no element in range matches a given matcher.
12478 template <typename Matcher>
12479 class NoneMatchMatcher final : public MatcherGenericBase {
12480 Matcher m_matcher;
12481 public:
12482 NoneMatchMatcher(Matcher matcher):
12483 m_matcher(CATCH_MOVE(matcher))
12484 {}
12485
12486 std::string describe() const override {
12487 return "none match " + m_matcher.describe();
12488 }
12489
12490 template <typename RangeLike>
12491 bool match(RangeLike&& rng) const {
12492 for (auto&& elem : rng) {
12493 if (m_matcher.match(elem)) {
12494 return false;
12495 }
12496 }
12497 return true;
12498 }
12499 };
12500
12501 // Matcher for checking that at least one element in range matches a given matcher.
12502 template <typename Matcher>
12503 class AnyMatchMatcher final : public MatcherGenericBase {
12504 Matcher m_matcher;
12505 public:
12506 AnyMatchMatcher(Matcher matcher):
12507 m_matcher(CATCH_MOVE(matcher))
12508 {}
12509
12510 std::string describe() const override {
12511 return "any match " + m_matcher.describe();
12512 }
12513
12514 template <typename RangeLike>
12515 bool match(RangeLike&& rng) const {
12516 for (auto&& elem : rng) {
12517 if (m_matcher.match(elem)) {
12518 return true;
12519 }
12520 }
12521 return false;
12522 }
12523 };
12524
12525 // Matcher for checking that all elements in range are true.
12526 class AllTrueMatcher final : public MatcherGenericBase {
12527 public:
12528 std::string describe() const override;
12529
12530 template <typename RangeLike>
12531 bool match(RangeLike&& rng) const {
12532 for (auto&& elem : rng) {
12533 if (!elem) {
12534 return false;
12535 }
12536 }
12537 return true;
12538 }
12539 };
12540
12541 // Matcher for checking that no element in range is true.
12542 class NoneTrueMatcher final : public MatcherGenericBase {
12543 public:
12544 std::string describe() const override;
12545
12546 template <typename RangeLike>
12547 bool match(RangeLike&& rng) const {
12548 for (auto&& elem : rng) {
12549 if (elem) {
12550 return false;
12551 }
12552 }
12553 return true;
12554 }
12555 };
12556
12557 // Matcher for checking that any element in range is true.
12558 class AnyTrueMatcher final : public MatcherGenericBase {
12559 public:
12560 std::string describe() const override;
12561
12562 template <typename RangeLike>
12563 bool match(RangeLike&& rng) const {
12564 for (auto&& elem : rng) {
12565 if (elem) {
12566 return true;
12567 }
12568 }
12569 return false;
12570 }
12571 };
12572
12573 // Creates a matcher that checks whether all elements in a range match a matcher
12574 template <typename Matcher>
12575 AllMatchMatcher<Matcher> AllMatch(Matcher&& matcher) {
12576 return { CATCH_FORWARD(matcher) };
12577 }
12578
12579 // Creates a matcher that checks whether no element in a range matches a matcher.
12580 template <typename Matcher>
12581 NoneMatchMatcher<Matcher> NoneMatch(Matcher&& matcher) {
12582 return { CATCH_FORWARD(matcher) };
12583 }
12584
12585 // Creates a matcher that checks whether any element in a range matches a matcher.
12586 template <typename Matcher>
12587 AnyMatchMatcher<Matcher> AnyMatch(Matcher&& matcher) {
12588 return { CATCH_FORWARD(matcher) };
12589 }
12590
12591 // Creates a matcher that checks whether all elements in a range are true
12592 AllTrueMatcher AllTrue();
12593
12594 // Creates a matcher that checks whether no element in a range is true
12595 NoneTrueMatcher NoneTrue();
12596
12597 // Creates a matcher that checks whether any element in a range is true
12598 AnyTrueMatcher AnyTrue();
12599 }
12600}
12601
12602#endif // CATCH_MATCHERS_QUANTIFIERS_HPP_INCLUDED
12603
12604
12605#ifndef CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
12606#define CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
12607
12608
12609#include <algorithm>
12610#include <utility>
12611
12612namespace Catch {
12613 namespace Matchers {
12614
12615 /**
12616 * Matcher for checking that an element contains the same
12617 * elements in the same order
12618 */
12619 template <typename TargetRangeLike, typename Equality>
12620 class RangeEqualsMatcher final : public MatcherGenericBase {
12621 TargetRangeLike m_desired;
12622 Equality m_predicate;
12623
12624 public:
12625 template <typename TargetRangeLike2, typename Equality2>
12626 constexpr
12627 RangeEqualsMatcher( TargetRangeLike2&& range,
12628 Equality2&& predicate ):
12629 m_desired( CATCH_FORWARD( range ) ),
12630 m_predicate( CATCH_FORWARD( predicate ) ) {}
12631
12632 template <typename RangeLike>
12633 constexpr
12634 bool match( RangeLike&& rng ) const {
12635 auto rng_start = begin( rng );
12636 const auto rng_end = end( rng );
12637 auto target_start = begin( m_desired );
12638 const auto target_end = end( m_desired );
12639
12640 while (rng_start != rng_end && target_start != target_end) {
12641 if (!m_predicate(*rng_start, *target_start)) {
12642 return false;
12643 }
12644 ++rng_start;
12645 ++target_start;
12646 }
12647 return rng_start == rng_end && target_start == target_end;
12648 }
12649
12650 std::string describe() const override {
12651 return "elements are " + Catch::Detail::stringify( m_desired );
12652 }
12653 };
12654
12655 /**
12656 * Matcher for checking that an element contains the same
12657 * elements (but not necessarily in the same order)
12658 */
12659 template <typename TargetRangeLike, typename Equality>
12660 class UnorderedRangeEqualsMatcher final : public MatcherGenericBase {
12661 TargetRangeLike m_desired;
12662 Equality m_predicate;
12663
12664 public:
12665 template <typename TargetRangeLike2, typename Equality2>
12666 constexpr
12667 UnorderedRangeEqualsMatcher( TargetRangeLike2&& range,
12668 Equality2&& predicate ):
12669 m_desired( CATCH_FORWARD( range ) ),
12670 m_predicate( CATCH_FORWARD( predicate ) ) {}
12671
12672 template <typename RangeLike>
12673 constexpr
12674 bool match( RangeLike&& rng ) const {
12675 using std::begin;
12676 using std::end;
12677 return Catch::Detail::is_permutation( begin( m_desired ),
12678 end( m_desired ),
12679 begin( rng ),
12680 end( rng ),
12681 m_predicate );
12682 }
12683
12684 std::string describe() const override {
12685 return "unordered elements are " +
12686 ::Catch::Detail::stringify( m_desired );
12687 }
12688 };
12689
12690 /**
12691 * Creates a matcher that checks if all elements in a range are equal
12692 * to all elements in another range.
12693 *
12694 * Uses `std::equal_to` to do the comparison
12695 */
12696 template <typename RangeLike>
12697 constexpr
12698 std::enable_if_t<!Detail::is_matcher<RangeLike>::value,
12699 RangeEqualsMatcher<RangeLike, std::equal_to<>>>
12700 RangeEquals( RangeLike&& range ) {
12701 return { CATCH_FORWARD( range ), std::equal_to<>{} };
12702 }
12703
12704 /**
12705 * Creates a matcher that checks if all elements in a range are equal
12706 * to all elements in another range.
12707 *
12708 * Uses to provided predicate `predicate` to do the comparisons
12709 */
12710 template <typename RangeLike, typename Equality>
12711 constexpr
12712 RangeEqualsMatcher<RangeLike, Equality>
12713 RangeEquals( RangeLike&& range, Equality&& predicate ) {
12714 return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
12715 }
12716
12717 /**
12718 * Creates a matcher that checks if all elements in a range are equal
12719 * to all elements in another range, in some permutation
12720 *
12721 * Uses `std::equal_to` to do the comparison
12722 */
12723 template <typename RangeLike>
12724 constexpr
12725 std::enable_if_t<
12726 !Detail::is_matcher<RangeLike>::value,
12727 UnorderedRangeEqualsMatcher<RangeLike, std::equal_to<>>>
12728 UnorderedRangeEquals( RangeLike&& range ) {
12729 return { CATCH_FORWARD( range ), std::equal_to<>{} };
12730 }
12731
12732 /**
12733 * Creates a matcher that checks if all elements in a range are equal
12734 * to all elements in another range, in some permutation.
12735 *
12736 * Uses to provided predicate `predicate` to do the comparisons
12737 */
12738 template <typename RangeLike, typename Equality>
12739 constexpr
12740 UnorderedRangeEqualsMatcher<RangeLike, Equality>
12741 UnorderedRangeEquals( RangeLike&& range, Equality&& predicate ) {
12742 return { CATCH_FORWARD( range ), CATCH_FORWARD( predicate ) };
12743 }
12744 } // namespace Matchers
12745} // namespace Catch
12746
12747#endif // CATCH_MATCHERS_RANGE_EQUALS_HPP_INCLUDED
12748
12749
12750#ifndef CATCH_MATCHERS_STRING_HPP_INCLUDED
12751#define CATCH_MATCHERS_STRING_HPP_INCLUDED
12752
12753
12754#include <string>
12755
12756namespace Catch {
12757namespace Matchers {
12758
12759 struct CasedString {
12760 CasedString( std::string const& str, CaseSensitive caseSensitivity );
12761 std::string adjustString( std::string const& str ) const;
12762 StringRef caseSensitivitySuffix() const;
12763
12764 CaseSensitive m_caseSensitivity;
12765 std::string m_str;
12766 };
12767
12768 class StringMatcherBase : public MatcherBase<std::string> {
12769 protected:
12770 CasedString m_comparator;
12771 StringRef m_operation;
12772
12773 public:
12774 StringMatcherBase( StringRef operation,
12775 CasedString const& comparator );
12776 std::string describe() const override;
12777 };
12778
12779 class StringEqualsMatcher final : public StringMatcherBase {
12780 public:
12781 StringEqualsMatcher( CasedString const& comparator );
12782 bool match( std::string const& source ) const override;
12783 };
12784 class StringContainsMatcher final : public StringMatcherBase {
12785 public:
12786 StringContainsMatcher( CasedString const& comparator );
12787 bool match( std::string const& source ) const override;
12788 };
12789 class StartsWithMatcher final : public StringMatcherBase {
12790 public:
12791 StartsWithMatcher( CasedString const& comparator );
12792 bool match( std::string const& source ) const override;
12793 };
12794 class EndsWithMatcher final : public StringMatcherBase {
12795 public:
12796 EndsWithMatcher( CasedString const& comparator );
12797 bool match( std::string const& source ) const override;
12798 };
12799
12800 class RegexMatcher final : public MatcherBase<std::string> {
12801 std::string m_regex;
12802 CaseSensitive m_caseSensitivity;
12803
12804 public:
12805 RegexMatcher( std::string regex, CaseSensitive caseSensitivity );
12806 bool match( std::string const& matchee ) const override;
12807 std::string describe() const override;
12808 };
12809
12810 //! Creates matcher that accepts strings that are exactly equal to `str`
12811 StringEqualsMatcher Equals( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
12812 //! Creates matcher that accepts strings that contain `str`
12813 StringContainsMatcher ContainsSubstring( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
12814 //! Creates matcher that accepts strings that _end_ with `str`
12815 EndsWithMatcher EndsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
12816 //! Creates matcher that accepts strings that _start_ with `str`
12817 StartsWithMatcher StartsWith( std::string const& str, CaseSensitive caseSensitivity = CaseSensitive::Yes );
12818 //! Creates matcher that accepts strings matching `regex`
12819 RegexMatcher Matches( std::string const& regex, CaseSensitive caseSensitivity = CaseSensitive::Yes );
12820
12821} // namespace Matchers
12822} // namespace Catch
12823
12824#endif // CATCH_MATCHERS_STRING_HPP_INCLUDED
12825
12826
12827#ifndef CATCH_MATCHERS_VECTOR_HPP_INCLUDED
12828#define CATCH_MATCHERS_VECTOR_HPP_INCLUDED
12829
12830
12831#include <algorithm>
12832
12833namespace Catch {
12834namespace Matchers {
12835
12836 template<typename T, typename Alloc>
12837 class VectorContainsElementMatcher final : public MatcherBase<std::vector<T, Alloc>> {
12838 T const& m_comparator;
12839
12840 public:
12841 VectorContainsElementMatcher(T const& comparator):
12842 m_comparator(comparator)
12843 {}
12844
12845 bool match(std::vector<T, Alloc> const& v) const override {
12846 for (auto const& el : v) {
12847 if (el == m_comparator) {
12848 return true;
12849 }
12850 }
12851 return false;
12852 }
12853
12854 std::string describe() const override {
12855 return "Contains: " + ::Catch::Detail::stringify( m_comparator );
12856 }
12857 };
12858
12859 template<typename T, typename AllocComp, typename AllocMatch>
12860 class ContainsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
12861 std::vector<T, AllocComp> const& m_comparator;
12862
12863 public:
12864 ContainsMatcher(std::vector<T, AllocComp> const& comparator):
12865 m_comparator( comparator )
12866 {}
12867
12868 bool match(std::vector<T, AllocMatch> const& v) const override {
12869 // !TBD: see note in EqualsMatcher
12870 if (m_comparator.size() > v.size())
12871 return false;
12872 for (auto const& comparator : m_comparator) {
12873 auto present = false;
12874 for (const auto& el : v) {
12875 if (el == comparator) {
12876 present = true;
12877 break;
12878 }
12879 }
12880 if (!present) {
12881 return false;
12882 }
12883 }
12884 return true;
12885 }
12886 std::string describe() const override {
12887 return "Contains: " + ::Catch::Detail::stringify( m_comparator );
12888 }
12889 };
12890
12891 template<typename T, typename AllocComp, typename AllocMatch>
12892 class EqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
12893 std::vector<T, AllocComp> const& m_comparator;
12894
12895 public:
12896 EqualsMatcher(std::vector<T, AllocComp> const& comparator):
12897 m_comparator( comparator )
12898 {}
12899
12900 bool match(std::vector<T, AllocMatch> const& v) const override {
12901 // !TBD: This currently works if all elements can be compared using !=
12902 // - a more general approach would be via a compare template that defaults
12903 // to using !=. but could be specialised for, e.g. std::vector<T> etc
12904 // - then just call that directly
12905 if ( m_comparator.size() != v.size() ) { return false; }
12906 for ( std::size_t i = 0; i < v.size(); ++i ) {
12907 if ( !( m_comparator[i] == v[i] ) ) { return false; }
12908 }
12909 return true;
12910 }
12911 std::string describe() const override {
12912 return "Equals: " + ::Catch::Detail::stringify( m_comparator );
12913 }
12914 };
12915
12916 template<typename T, typename AllocComp, typename AllocMatch>
12917 class ApproxMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
12918 std::vector<T, AllocComp> const& m_comparator;
12919 mutable Catch::Approx approx = Catch::Approx::custom();
12920
12921 public:
12922 ApproxMatcher(std::vector<T, AllocComp> const& comparator):
12923 m_comparator( comparator )
12924 {}
12925
12926 bool match(std::vector<T, AllocMatch> const& v) const override {
12927 if (m_comparator.size() != v.size())
12928 return false;
12929 for (std::size_t i = 0; i < v.size(); ++i)
12930 if (m_comparator[i] != approx(v[i]))
12931 return false;
12932 return true;
12933 }
12934 std::string describe() const override {
12935 return "is approx: " + ::Catch::Detail::stringify( m_comparator );
12936 }
12937 template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
12938 ApproxMatcher& epsilon( T const& newEpsilon ) {
12939 approx.epsilon(static_cast<double>(newEpsilon));
12940 return *this;
12941 }
12942 template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
12943 ApproxMatcher& margin( T const& newMargin ) {
12944 approx.margin(static_cast<double>(newMargin));
12945 return *this;
12946 }
12947 template <typename = std::enable_if_t<std::is_constructible<double, T>::value>>
12948 ApproxMatcher& scale( T const& newScale ) {
12949 approx.scale(static_cast<double>(newScale));
12950 return *this;
12951 }
12952 };
12953
12954 template<typename T, typename AllocComp, typename AllocMatch>
12955 class UnorderedEqualsMatcher final : public MatcherBase<std::vector<T, AllocMatch>> {
12956 std::vector<T, AllocComp> const& m_target;
12957
12958 public:
12959 UnorderedEqualsMatcher(std::vector<T, AllocComp> const& target):
12960 m_target(target)
12961 {}
12962 bool match(std::vector<T, AllocMatch> const& vec) const override {
12963 if (m_target.size() != vec.size()) {
12964 return false;
12965 }
12966 return std::is_permutation(m_target.begin(), m_target.end(), vec.begin());
12967 }
12968
12969 std::string describe() const override {
12970 return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target);
12971 }
12972 };
12973
12974
12975 // The following functions create the actual matcher objects.
12976 // This allows the types to be inferred
12977
12978 //! Creates a matcher that matches vectors that contain all elements in `comparator`
12979 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
12980 ContainsMatcher<T, AllocComp, AllocMatch> Contains( std::vector<T, AllocComp> const& comparator ) {
12981 return ContainsMatcher<T, AllocComp, AllocMatch>(comparator);
12982 }
12983
12984 //! Creates a matcher that matches vectors that contain `comparator` as an element
12985 template<typename T, typename Alloc = std::allocator<T>>
12986 VectorContainsElementMatcher<T, Alloc> VectorContains( T const& comparator ) {
12987 return VectorContainsElementMatcher<T, Alloc>(comparator);
12988 }
12989
12990 //! Creates a matcher that matches vectors that are exactly equal to `comparator`
12991 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
12992 EqualsMatcher<T, AllocComp, AllocMatch> Equals( std::vector<T, AllocComp> const& comparator ) {
12993 return EqualsMatcher<T, AllocComp, AllocMatch>(comparator);
12994 }
12995
12996 //! Creates a matcher that matches vectors that `comparator` as an element
12997 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
12998 ApproxMatcher<T, AllocComp, AllocMatch> Approx( std::vector<T, AllocComp> const& comparator ) {
12999 return ApproxMatcher<T, AllocComp, AllocMatch>(comparator);
13000 }
13001
13002 //! Creates a matcher that matches vectors that is equal to `target` modulo permutation
13003 template<typename T, typename AllocComp = std::allocator<T>, typename AllocMatch = AllocComp>
13004 UnorderedEqualsMatcher<T, AllocComp, AllocMatch> UnorderedEquals(std::vector<T, AllocComp> const& target) {
13005 return UnorderedEqualsMatcher<T, AllocComp, AllocMatch>(target);
13006 }
13007
13008} // namespace Matchers
13009} // namespace Catch
13010
13011#endif // CATCH_MATCHERS_VECTOR_HPP_INCLUDED
13012
13013#endif // CATCH_MATCHERS_ALL_HPP_INCLUDED
13014
13015
13016/** \file
13017 * This is a convenience header for Catch2's Reporter support. It includes
13018 * **all** of Catch2 headers related to reporters, including all reporters.
13019 *
13020 * Generally the Catch2 users should use specific includes they need,
13021 * but this header can be used instead for ease-of-experimentation, or
13022 * just plain convenience, at the cost of (significantly) increased
13023 * compilation times.
13024 *
13025 * When a new header (reporter) is added to either the `reporter` folder,
13026 * or to the corresponding internal subfolder, it should be added here.
13027 */
13028
13029#ifndef CATCH_REPORTERS_ALL_HPP_INCLUDED
13030#define CATCH_REPORTERS_ALL_HPP_INCLUDED
13031
13032
13033
13034#ifndef CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
13035#define CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
13036
13037
13038
13039#ifndef CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
13040#define CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
13041
13042
13043
13044#ifndef CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
13045#define CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
13046
13047
13048#include <map>
13049#include <string>
13050
13051namespace Catch {
13052 class ColourImpl;
13053
13054 /**
13055 * This is the base class for all reporters.
13056 *
13057 * If are writing a reporter, you must derive from this type, or one
13058 * of the helper reporter bases that are derived from this type.
13059 *
13060 * ReporterBase centralizes handling of various common tasks in reporters,
13061 * like storing the right stream for the reporters to write to, and
13062 * providing the default implementation of the different listing events.
13063 */
13064 class ReporterBase : public IEventListener {
13065 protected:
13066 //! The stream wrapper as passed to us by outside code
13067 Detail::unique_ptr<IStream> m_wrapped_stream;
13068 //! Cached output stream from `m_wrapped_stream` to reduce
13069 //! number of indirect calls needed to write output.
13070 std::ostream& m_stream;
13071 //! Colour implementation this reporter was configured for
13072 Detail::unique_ptr<ColourImpl> m_colour;
13073 //! The custom reporter options user passed down to the reporter
13074 std::map<std::string, std::string> m_customOptions;
13075
13076 public:
13077 ReporterBase( ReporterConfig&& config );
13078 ~ReporterBase() override; // = default;
13079
13080 /**
13081 * Provides a simple default listing of reporters.
13082 *
13083 * Should look roughly like the reporter listing in v2 and earlier
13084 * versions of Catch2.
13085 */
13086 void listReporters(
13087 std::vector<ReporterDescription> const& descriptions ) override;
13088 /**
13089 * Provides a simple default listing of listeners
13090 *
13091 * Looks similarly to listing of reporters, but with listener type
13092 * instead of reporter name.
13093 */
13094 void listListeners(
13095 std::vector<ListenerDescription> const& descriptions ) override;
13096 /**
13097 * Provides a simple default listing of tests.
13098 *
13099 * Should look roughly like the test listing in v2 and earlier versions
13100 * of Catch2. Especially supports low-verbosity listing that mimics the
13101 * old `--list-test-names-only` output.
13102 */
13103 void listTests( std::vector<TestCaseHandle> const& tests ) override;
13104 /**
13105 * Provides a simple default listing of tags.
13106 *
13107 * Should look roughly like the tag listing in v2 and earlier versions
13108 * of Catch2.
13109 */
13110 void listTags( std::vector<TagInfo> const& tags ) override;
13111 };
13112} // namespace Catch
13113
13114#endif // CATCH_REPORTER_COMMON_BASE_HPP_INCLUDED
13115
13116#include <vector>
13117
13118namespace Catch {
13119
13120 class StreamingReporterBase : public ReporterBase {
13121 public:
13122 // GCC5 compat: we cannot use inherited constructor, because it
13123 // doesn't implement backport of P0136
13124 StreamingReporterBase(ReporterConfig&& _config):
13125 ReporterBase(CATCH_MOVE(_config))
13126 {}
13127 ~StreamingReporterBase() override;
13128
13129 void benchmarkPreparing( StringRef ) override {}
13130 void benchmarkStarting( BenchmarkInfo const& ) override {}
13131 void benchmarkEnded( BenchmarkStats<> const& ) override {}
13132 void benchmarkFailed( StringRef ) override {}
13133
13134 void fatalErrorEncountered( StringRef /*error*/ ) override {}
13135 void noMatchingTestCases( StringRef /*unmatchedSpec*/ ) override {}
13136 void reportInvalidTestSpec( StringRef /*invalidArgument*/ ) override {}
13137
13138 void testRunStarting( TestRunInfo const& _testRunInfo ) override;
13139
13140 void testCaseStarting(TestCaseInfo const& _testInfo) override {
13141 currentTestCaseInfo = &_testInfo;
13142 }
13143 void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
13144 void sectionStarting(SectionInfo const& _sectionInfo) override {
13145 m_sectionStack.push_back(_sectionInfo);
13146 }
13147
13148 void assertionStarting( AssertionInfo const& ) override {}
13149 void assertionEnded( AssertionStats const& ) override {}
13150
13151 void sectionEnded(SectionStats const& /* _sectionStats */) override {
13152 m_sectionStack.pop_back();
13153 }
13154 void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
13155 void testCaseEnded(TestCaseStats const& /* _testCaseStats */) override {
13156 currentTestCaseInfo = nullptr;
13157 }
13158 void testRunEnded( TestRunStats const& /* _testRunStats */ ) override;
13159
13160 void skipTest(TestCaseInfo const&) override {
13161 // Don't do anything with this by default.
13162 // It can optionally be overridden in the derived class.
13163 }
13164
13165 protected:
13166 TestRunInfo currentTestRunInfo{ "test run has not started yet"_sr };
13167 TestCaseInfo const* currentTestCaseInfo = nullptr;
13168
13169 //! Stack of all _active_ sections in the _current_ test case
13170 std::vector<SectionInfo> m_sectionStack;
13171 };
13172
13173} // end namespace Catch
13174
13175#endif // CATCH_REPORTER_STREAMING_BASE_HPP_INCLUDED
13176
13177#include <string>
13178
13179namespace Catch {
13180
13181 class AutomakeReporter final : public StreamingReporterBase {
13182 public:
13183 // GCC5 compat: we cannot use inherited constructor, because it
13184 // doesn't implement backport of P0136
13185 AutomakeReporter(ReporterConfig&& _config):
13186 StreamingReporterBase(CATCH_MOVE(_config))
13187 {}
13188 ~AutomakeReporter() override;
13189
13190 static std::string getDescription() {
13191 using namespace std::string_literals;
13192 return "Reports test results in the format of Automake .trs files"s;
13193 }
13194
13195 void testCaseEnded(TestCaseStats const& _testCaseStats) override;
13196 void skipTest(TestCaseInfo const& testInfo) override;
13197 };
13198
13199} // end namespace Catch
13200
13201#endif // CATCH_REPORTER_AUTOMAKE_HPP_INCLUDED
13202
13203
13204#ifndef CATCH_REPORTER_COMPACT_HPP_INCLUDED
13205#define CATCH_REPORTER_COMPACT_HPP_INCLUDED
13206
13207
13208
13209
13210namespace Catch {
13211
13212 class CompactReporter final : public StreamingReporterBase {
13213 public:
13214 using StreamingReporterBase::StreamingReporterBase;
13215
13216 ~CompactReporter() override;
13217
13218 static std::string getDescription();
13219
13220 void noMatchingTestCases( StringRef unmatchedSpec ) override;
13221
13222 void testRunStarting( TestRunInfo const& _testInfo ) override;
13223
13224 void assertionEnded(AssertionStats const& _assertionStats) override;
13225
13226 void sectionEnded(SectionStats const& _sectionStats) override;
13227
13228 void testRunEnded(TestRunStats const& _testRunStats) override;
13229
13230 };
13231
13232} // end namespace Catch
13233
13234#endif // CATCH_REPORTER_COMPACT_HPP_INCLUDED
13235
13236
13237#ifndef CATCH_REPORTER_CONSOLE_HPP_INCLUDED
13238#define CATCH_REPORTER_CONSOLE_HPP_INCLUDED
13239
13240
13241namespace Catch {
13242 // Fwd decls
13243 class TablePrinter;
13244
13245 class ConsoleReporter final : public StreamingReporterBase {
13246 Detail::unique_ptr<TablePrinter> m_tablePrinter;
13247
13248 public:
13249 ConsoleReporter(ReporterConfig&& config);
13250 ~ConsoleReporter() override;
13251 static std::string getDescription();
13252
13253 void noMatchingTestCases( StringRef unmatchedSpec ) override;
13254 void reportInvalidTestSpec( StringRef arg ) override;
13255
13256 void assertionStarting(AssertionInfo const&) override;
13257
13258 void assertionEnded(AssertionStats const& _assertionStats) override;
13259
13260 void sectionStarting(SectionInfo const& _sectionInfo) override;
13261 void sectionEnded(SectionStats const& _sectionStats) override;
13262
13263 void benchmarkPreparing( StringRef name ) override;
13264 void benchmarkStarting(BenchmarkInfo const& info) override;
13265 void benchmarkEnded(BenchmarkStats<> const& stats) override;
13266 void benchmarkFailed( StringRef error ) override;
13267
13268 void testCaseEnded(TestCaseStats const& _testCaseStats) override;
13269 void testRunEnded(TestRunStats const& _testRunStats) override;
13270 void testRunStarting(TestRunInfo const& _testRunInfo) override;
13271
13272 private:
13273 void lazyPrint();
13274
13275 void lazyPrintWithoutClosingBenchmarkTable();
13276 void lazyPrintRunInfo();
13277 void printTestCaseAndSectionHeader();
13278
13279 void printClosedHeader(std::string const& _name);
13280 void printOpenHeader(std::string const& _name);
13281
13282 // if string has a : in first line will set indent to follow it on
13283 // subsequent lines
13284 void printHeaderString(std::string const& _string, std::size_t indent = 0);
13285
13286 void printTotalsDivider(Totals const& totals);
13287
13288 bool m_headerPrinted = false;
13289 bool m_testRunInfoPrinted = false;
13290 };
13291
13292} // end namespace Catch
13293
13294#endif // CATCH_REPORTER_CONSOLE_HPP_INCLUDED
13295
13296
13297#ifndef CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
13298#define CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
13299
13300
13301#include <string>
13302#include <vector>
13303
13304namespace Catch {
13305
13306 namespace Detail {
13307
13308 //! Represents either an assertion or a benchmark result to be handled by cumulative reporter later
13309 class AssertionOrBenchmarkResult {
13310 // This should really be a variant, but this is much faster
13311 // to write and the data layout here is already terrible
13312 // enough that we do not have to care about the object size.
13313 Optional<AssertionStats> m_assertion;
13314 Optional<BenchmarkStats<>> m_benchmark;
13315 public:
13316 AssertionOrBenchmarkResult(AssertionStats const& assertion);
13317 AssertionOrBenchmarkResult(BenchmarkStats<> const& benchmark);
13318
13319 bool isAssertion() const;
13320 bool isBenchmark() const;
13321
13322 AssertionStats const& asAssertion() const;
13323 BenchmarkStats<> const& asBenchmark() const;
13324 };
13325 }
13326
13327 /**
13328 * Utility base for reporters that need to handle all results at once
13329 *
13330 * It stores tree of all test cases, sections and assertions, and after the
13331 * test run is finished, calls into `testRunEndedCumulative` to pass the
13332 * control to the deriving class.
13333 *
13334 * If you are deriving from this class and override any testing related
13335 * member functions, you should first call into the base's implementation to
13336 * avoid breaking the tree construction.
13337 *
13338 * Due to the way this base functions, it has to expand assertions up-front,
13339 * even if they are later unused (e.g. because the deriving reporter does
13340 * not report successful assertions, or because the deriving reporter does
13341 * not use assertion expansion at all). Derived classes can use two
13342 * customization points, `m_shouldStoreSuccesfulAssertions` and
13343 * `m_shouldStoreFailedAssertions`, to disable the expansion and gain extra
13344 * performance. **Accessing the assertion expansions if it wasn't stored is
13345 * UB.**
13346 */
13347 class CumulativeReporterBase : public ReporterBase {
13348 public:
13349 template<typename T, typename ChildNodeT>
13350 struct Node {
13351 explicit Node( T const& _value ) : value( _value ) {}
13352
13353 using ChildNodes = std::vector<Detail::unique_ptr<ChildNodeT>>;
13354 T value;
13355 ChildNodes children;
13356 };
13357 struct SectionNode {
13358 explicit SectionNode(SectionStats const& _stats) : stats(_stats) {}
13359
13360 bool operator == (SectionNode const& other) const {
13361 return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
13362 }
13363
13364 bool hasAnyAssertions() const;
13365
13366 SectionStats stats;
13367 std::vector<Detail::unique_ptr<SectionNode>> childSections;
13368 std::vector<Detail::AssertionOrBenchmarkResult> assertionsAndBenchmarks;
13369 std::string stdOut;
13370 std::string stdErr;
13371 };
13372
13373
13374 using TestCaseNode = Node<TestCaseStats, SectionNode>;
13375 using TestRunNode = Node<TestRunStats, TestCaseNode>;
13376
13377 // GCC5 compat: we cannot use inherited constructor, because it
13378 // doesn't implement backport of P0136
13379 CumulativeReporterBase(ReporterConfig&& _config):
13380 ReporterBase(CATCH_MOVE(_config))
13381 {}
13382 ~CumulativeReporterBase() override;
13383
13384 void benchmarkPreparing( StringRef ) override {}
13385 void benchmarkStarting( BenchmarkInfo const& ) override {}
13386 void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
13387 void benchmarkFailed( StringRef ) override {}
13388
13389 void noMatchingTestCases( StringRef ) override {}
13390 void reportInvalidTestSpec( StringRef ) override {}
13391 void fatalErrorEncountered( StringRef /*error*/ ) override {}
13392
13393 void testRunStarting( TestRunInfo const& ) override {}
13394
13395 void testCaseStarting( TestCaseInfo const& ) override {}
13396 void testCasePartialStarting( TestCaseInfo const&, uint64_t ) override {}
13397 void sectionStarting( SectionInfo const& sectionInfo ) override;
13398
13399 void assertionStarting( AssertionInfo const& ) override {}
13400
13401 void assertionEnded( AssertionStats const& assertionStats ) override;
13402 void sectionEnded( SectionStats const& sectionStats ) override;
13403 void testCasePartialEnded( TestCaseStats const&, uint64_t ) override {}
13404 void testCaseEnded( TestCaseStats const& testCaseStats ) override;
13405 void testRunEnded( TestRunStats const& testRunStats ) override;
13406 //! Customization point: called after last test finishes (testRunEnded has been handled)
13407 virtual void testRunEndedCumulative() = 0;
13408
13409 void skipTest(TestCaseInfo const&) override {}
13410
13411 protected:
13412 //! Should the cumulative base store the assertion expansion for successful assertions?
13413 bool m_shouldStoreSuccesfulAssertions = true;
13414 //! Should the cumulative base store the assertion expansion for failed assertions?
13415 bool m_shouldStoreFailedAssertions = true;
13416
13417 // We need lazy construction here. We should probably refactor it
13418 // later, after the events are redone.
13419 //! The root node of the test run tree.
13420 Detail::unique_ptr<TestRunNode> m_testRun;
13421
13422 private:
13423 // Note: We rely on pointer identity being stable, which is why
13424 // we store pointers to the nodes rather than the values.
13425 std::vector<Detail::unique_ptr<TestCaseNode>> m_testCases;
13426 // Root section of the _current_ test case
13427 Detail::unique_ptr<SectionNode> m_rootSection;
13428 // Deepest section of the _current_ test case
13429 SectionNode* m_deepestSection = nullptr;
13430 // Stack of _active_ sections in the _current_ test case
13431 std::vector<SectionNode*> m_sectionStack;
13432 };
13433
13434} // end namespace Catch
13435
13436#endif // CATCH_REPORTER_CUMULATIVE_BASE_HPP_INCLUDED
13437
13438
13439#ifndef CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
13440#define CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
13441
13442
13443namespace Catch {
13444
13445 /**
13446 * Base class to simplify implementing listeners.
13447 *
13448 * Provides empty default implementation for all IEventListener member
13449 * functions, so that a listener implementation can pick which
13450 * member functions it actually cares about.
13451 */
13452 class EventListenerBase : public IEventListener {
13453 public:
13454 using IEventListener::IEventListener;
13455
13456 void reportInvalidTestSpec( StringRef unmatchedSpec ) override;
13457 void fatalErrorEncountered( StringRef error ) override;
13458
13459 void benchmarkPreparing( StringRef name ) override;
13460 void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
13461 void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
13462 void benchmarkFailed( StringRef error ) override;
13463
13464 void assertionStarting( AssertionInfo const& assertionInfo ) override;
13465 void assertionEnded( AssertionStats const& assertionStats ) override;
13466
13467 void listReporters(
13468 std::vector<ReporterDescription> const& descriptions ) override;
13469 void listListeners(
13470 std::vector<ListenerDescription> const& descriptions ) override;
13471 void listTests( std::vector<TestCaseHandle> const& tests ) override;
13472 void listTags( std::vector<TagInfo> const& tagInfos ) override;
13473
13474 void noMatchingTestCases( StringRef unmatchedSpec ) override;
13475 void testRunStarting( TestRunInfo const& testRunInfo ) override;
13476 void testCaseStarting( TestCaseInfo const& testInfo ) override;
13477 void testCasePartialStarting( TestCaseInfo const& testInfo,
13478 uint64_t partNumber ) override;
13479 void sectionStarting( SectionInfo const& sectionInfo ) override;
13480 void sectionEnded( SectionStats const& sectionStats ) override;
13481 void testCasePartialEnded( TestCaseStats const& testCaseStats,
13482 uint64_t partNumber ) override;
13483 void testCaseEnded( TestCaseStats const& testCaseStats ) override;
13484 void testRunEnded( TestRunStats const& testRunStats ) override;
13485 void skipTest( TestCaseInfo const& testInfo ) override;
13486 };
13487
13488} // end namespace Catch
13489
13490#endif // CATCH_REPORTER_EVENT_LISTENER_HPP_INCLUDED
13491
13492
13493#ifndef CATCH_REPORTER_HELPERS_HPP_INCLUDED
13494#define CATCH_REPORTER_HELPERS_HPP_INCLUDED
13495
13496#include <iosfwd>
13497#include <string>
13498#include <vector>
13499
13500
13501namespace Catch {
13502
13503 class IConfig;
13504 class TestCaseHandle;
13505 class ColourImpl;
13506
13507 // Returns double formatted as %.3f (format expected on output)
13508 std::string getFormattedDuration( double duration );
13509
13510 //! Should the reporter show duration of test given current configuration?
13511 bool shouldShowDuration( IConfig const& config, double duration );
13512
13513 std::string serializeFilters( std::vector<std::string> const& filters );
13514
13515 struct lineOfChars {
13516 char c;
13517 constexpr lineOfChars( char c_ ): c( c_ ) {}
13518
13519 friend std::ostream& operator<<( std::ostream& out, lineOfChars value );
13520 };
13521
13522 /**
13523 * Lists reporter descriptions to the provided stream in user-friendly
13524 * format
13525 *
13526 * Used as the default listing implementation by the first party reporter
13527 * bases. The output should be backwards compatible with the output of
13528 * Catch2 v2 binaries.
13529 */
13530 void
13531 defaultListReporters( std::ostream& out,
13532 std::vector<ReporterDescription> const& descriptions,
13533 Verbosity verbosity );
13534
13535 /**
13536 * Lists listeners descriptions to the provided stream in user-friendly
13537 * format
13538 */
13539 void defaultListListeners( std::ostream& out,
13540 std::vector<ListenerDescription> const& descriptions );
13541
13542 /**
13543 * Lists tag information to the provided stream in user-friendly format
13544 *
13545 * Used as the default listing implementation by the first party reporter
13546 * bases. The output should be backwards compatible with the output of
13547 * Catch2 v2 binaries.
13548 */
13549 void defaultListTags( std::ostream& out, std::vector<TagInfo> const& tags, bool isFiltered );
13550
13551 /**
13552 * Lists test case information to the provided stream in user-friendly
13553 * format
13554 *
13555 * Used as the default listing implementation by the first party reporter
13556 * bases. The output is backwards compatible with the output of Catch2
13557 * v2 binaries, and also supports the format specific to the old
13558 * `--list-test-names-only` option, for people who used it in integrations.
13559 */
13560 void defaultListTests( std::ostream& out,
13561 ColourImpl* streamColour,
13562 std::vector<TestCaseHandle> const& tests,
13563 bool isFiltered,
13564 Verbosity verbosity );
13565
13566 /**
13567 * Prints test run totals to the provided stream in user-friendly format
13568 *
13569 * Used by the console and compact reporters.
13570 */
13571 void printTestRunTotals( std::ostream& stream,
13572 ColourImpl& streamColour,
13573 Totals const& totals );
13574
13575} // end namespace Catch
13576
13577#endif // CATCH_REPORTER_HELPERS_HPP_INCLUDED
13578
13579
13580
13581#ifndef CATCH_REPORTER_JSON_HPP_INCLUDED
13582#define CATCH_REPORTER_JSON_HPP_INCLUDED
13583
13584
13585#include <stack>
13586
13587namespace Catch {
13588 class JsonReporter : public StreamingReporterBase {
13589 public:
13590 JsonReporter( ReporterConfig&& config );
13591
13592 ~JsonReporter() override;
13593
13594 static std::string getDescription();
13595
13596 public: // StreamingReporterBase
13597 void testRunStarting( TestRunInfo const& runInfo ) override;
13598 void testRunEnded( TestRunStats const& runStats ) override;
13599
13600 void testCaseStarting( TestCaseInfo const& tcInfo ) override;
13601 void testCaseEnded( TestCaseStats const& tcStats ) override;
13602
13603 void testCasePartialStarting( TestCaseInfo const& tcInfo,
13604 uint64_t index ) override;
13605 void testCasePartialEnded( TestCaseStats const& tcStats,
13606 uint64_t index ) override;
13607
13608 void sectionStarting( SectionInfo const& sectionInfo ) override;
13609 void sectionEnded( SectionStats const& sectionStats ) override;
13610
13611 void assertionStarting( AssertionInfo const& assertionInfo ) override;
13612 void assertionEnded( AssertionStats const& assertionStats ) override;
13613
13614 //void testRunEndedCumulative() override;
13615
13616 void benchmarkPreparing( StringRef name ) override;
13617 void benchmarkStarting( BenchmarkInfo const& ) override;
13618 void benchmarkEnded( BenchmarkStats<> const& ) override;
13619 void benchmarkFailed( StringRef error ) override;
13620
13621 void listReporters(
13622 std::vector<ReporterDescription> const& descriptions ) override;
13623 void listListeners(
13624 std::vector<ListenerDescription> const& descriptions ) override;
13625 void listTests( std::vector<TestCaseHandle> const& tests ) override;
13626 void listTags( std::vector<TagInfo> const& tags ) override;
13627
13628 private:
13629 Timer m_testCaseTimer;
13630 enum class Writer {
13631 Object,
13632 Array
13633 };
13634
13635 JsonArrayWriter& startArray();
13636 JsonArrayWriter& startArray( StringRef key );
13637
13638 JsonObjectWriter& startObject();
13639 JsonObjectWriter& startObject( StringRef key );
13640
13641 void endObject();
13642 void endArray();
13643
13644 bool isInside( Writer writer );
13645
13646 void startListing();
13647 void endListing();
13648
13649 // Invariant:
13650 // When m_writers is not empty and its top element is
13651 // - Writer::Object, then m_objectWriters is not be empty
13652 // - Writer::Array, then m_arrayWriters shall not be empty
13653 std::stack<JsonObjectWriter> m_objectWriters{};
13654 std::stack<JsonArrayWriter> m_arrayWriters{};
13655 std::stack<Writer> m_writers{};
13656
13657 bool m_startedListing = false;
13658
13659 // std::size_t m_sectionDepth = 0;
13660 // std::size_t m_sectionStarted = 0;
13661 };
13662} // namespace Catch
13663
13664#endif // CATCH_REPORTER_JSON_HPP_INCLUDED
13665
13666
13667#ifndef CATCH_REPORTER_JUNIT_HPP_INCLUDED
13668#define CATCH_REPORTER_JUNIT_HPP_INCLUDED
13669
13670
13671
13672namespace Catch {
13673
13674 class JunitReporter final : public CumulativeReporterBase {
13675 public:
13676 JunitReporter(ReporterConfig&& _config);
13677
13678 static std::string getDescription();
13679
13680 void testRunStarting(TestRunInfo const& runInfo) override;
13681
13682 void testCaseStarting(TestCaseInfo const& testCaseInfo) override;
13683 void assertionEnded(AssertionStats const& assertionStats) override;
13684
13685 void testCaseEnded(TestCaseStats const& testCaseStats) override;
13686
13687 void testRunEndedCumulative() override;
13688
13689 private:
13690 void writeRun(TestRunNode const& testRunNode, double suiteTime);
13691
13692 void writeTestCase(TestCaseNode const& testCaseNode);
13693
13694 void writeSection( std::string const& className,
13695 std::string const& rootName,
13696 SectionNode const& sectionNode,
13697 bool testOkToFail );
13698
13699 void writeAssertions(SectionNode const& sectionNode);
13700 void writeAssertion(AssertionStats const& stats);
13701
13702 XmlWriter xml;
13703 Timer suiteTimer;
13704 std::string stdOutForSuite;
13705 std::string stdErrForSuite;
13706 unsigned int unexpectedExceptions = 0;
13707 bool m_okToFail = false;
13708 };
13709
13710} // end namespace Catch
13711
13712#endif // CATCH_REPORTER_JUNIT_HPP_INCLUDED
13713
13714
13715#ifndef CATCH_REPORTER_MULTI_HPP_INCLUDED
13716#define CATCH_REPORTER_MULTI_HPP_INCLUDED
13717
13718
13719namespace Catch {
13720
13721 class MultiReporter final : public IEventListener {
13722 /*
13723 * Stores all added reporters and listeners
13724 *
13725 * All Listeners are stored before all reporters, and individual
13726 * listeners/reporters are stored in order of insertion.
13727 */
13728 std::vector<IEventListenerPtr> m_reporterLikes;
13729 bool m_haveNoncapturingReporters = false;
13730
13731 // Keep track of how many listeners we have already inserted,
13732 // so that we can insert them into the main vector at the right place
13733 size_t m_insertedListeners = 0;
13734
13735 void updatePreferences(IEventListener const& reporterish);
13736
13737 public:
13738 using IEventListener::IEventListener;
13739
13740 void addListener( IEventListenerPtr&& listener );
13741 void addReporter( IEventListenerPtr&& reporter );
13742
13743 public: // IEventListener
13744
13745 void noMatchingTestCases( StringRef unmatchedSpec ) override;
13746 void fatalErrorEncountered( StringRef error ) override;
13747 void reportInvalidTestSpec( StringRef arg ) override;
13748
13749 void benchmarkPreparing( StringRef name ) override;
13750 void benchmarkStarting( BenchmarkInfo const& benchmarkInfo ) override;
13751 void benchmarkEnded( BenchmarkStats<> const& benchmarkStats ) override;
13752 void benchmarkFailed( StringRef error ) override;
13753
13754 void testRunStarting( TestRunInfo const& testRunInfo ) override;
13755 void testCaseStarting( TestCaseInfo const& testInfo ) override;
13756 void testCasePartialStarting(TestCaseInfo const& testInfo, uint64_t partNumber) override;
13757 void sectionStarting( SectionInfo const& sectionInfo ) override;
13758 void assertionStarting( AssertionInfo const& assertionInfo ) override;
13759
13760 void assertionEnded( AssertionStats const& assertionStats ) override;
13761 void sectionEnded( SectionStats const& sectionStats ) override;
13762 void testCasePartialEnded(TestCaseStats const& testStats, uint64_t partNumber) override;
13763 void testCaseEnded( TestCaseStats const& testCaseStats ) override;
13764 void testRunEnded( TestRunStats const& testRunStats ) override;
13765
13766 void skipTest( TestCaseInfo const& testInfo ) override;
13767
13768 void listReporters(std::vector<ReporterDescription> const& descriptions) override;
13769 void listListeners(std::vector<ListenerDescription> const& descriptions) override;
13770 void listTests(std::vector<TestCaseHandle> const& tests) override;
13771 void listTags(std::vector<TagInfo> const& tags) override;
13772
13773
13774 };
13775
13776} // end namespace Catch
13777
13778#endif // CATCH_REPORTER_MULTI_HPP_INCLUDED
13779
13780
13781#ifndef CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
13782#define CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
13783
13784
13785#include <type_traits>
13786
13787namespace Catch {
13788
13789 namespace Detail {
13790
13791 template <typename T, typename = void>
13792 struct has_description : std::false_type {};
13793
13794 template <typename T>
13795 struct has_description<
13796 T,
13797 void_t<decltype( T::getDescription() )>>
13798 : std::true_type {};
13799
13800 //! Indirection for reporter registration, so that the error handling is
13801 //! independent on the reporter's concrete type
13802 void registerReporterImpl( std::string const& name,
13803 IReporterFactoryPtr reporterPtr );
13804 //! Actually registers the factory, independent on listener's concrete type
13805 void registerListenerImpl( Detail::unique_ptr<EventListenerFactory> listenerFactory );
13806 } // namespace Detail
13807
13808 class IEventListener;
13809 using IEventListenerPtr = Detail::unique_ptr<IEventListener>;
13810
13811 template <typename T>
13812 class ReporterFactory : public IReporterFactory {
13813
13814 IEventListenerPtr create( ReporterConfig&& config ) const override {
13815 return Detail::make_unique<T>( CATCH_MOVE(config) );
13816 }
13817
13818 std::string getDescription() const override {
13819 return T::getDescription();
13820 }
13821 };
13822
13823
13824 template<typename T>
13825 class ReporterRegistrar {
13826 public:
13827 explicit ReporterRegistrar( std::string const& name ) {
13828 registerReporterImpl( name,
13829 Detail::make_unique<ReporterFactory<T>>() );
13830 }
13831 };
13832
13833 template<typename T>
13834 class ListenerRegistrar {
13835
13836 class TypedListenerFactory : public EventListenerFactory {
13837 StringRef m_listenerName;
13838
13839 std::string getDescriptionImpl( std::true_type ) const {
13840 return T::getDescription();
13841 }
13842
13843 std::string getDescriptionImpl( std::false_type ) const {
13844 return "(No description provided)";
13845 }
13846
13847 public:
13848 TypedListenerFactory( StringRef listenerName ):
13849 m_listenerName( listenerName ) {}
13850
13851 IEventListenerPtr create( IConfig const* config ) const override {
13852 return Detail::make_unique<T>( config );
13853 }
13854
13855 StringRef getName() const override {
13856 return m_listenerName;
13857 }
13858
13859 std::string getDescription() const override {
13860 return getDescriptionImpl( Detail::has_description<T>{} );
13861 }
13862 };
13863
13864 public:
13865 ListenerRegistrar(StringRef listenerName) {
13866 registerListenerImpl( Detail::make_unique<TypedListenerFactory>(listenerName) );
13867 }
13868 };
13869}
13870
13871#if !defined(CATCH_CONFIG_DISABLE)
13872
13873# define CATCH_REGISTER_REPORTER( name, reporterType ) \
13874 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
13875 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
13876 namespace { \
13877 Catch::ReporterRegistrar<reporterType> INTERNAL_CATCH_UNIQUE_NAME( \
13878 catch_internal_RegistrarFor )( name ); \
13879 } \
13880 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
13881
13882# define CATCH_REGISTER_LISTENER( listenerType ) \
13883 CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \
13884 CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \
13885 namespace { \
13886 Catch::ListenerRegistrar<listenerType> INTERNAL_CATCH_UNIQUE_NAME( \
13887 catch_internal_RegistrarFor )( #listenerType##_catch_sr ); \
13888 } \
13889 CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION
13890
13891#else // CATCH_CONFIG_DISABLE
13892
13893#define CATCH_REGISTER_REPORTER(name, reporterType)
13894#define CATCH_REGISTER_LISTENER(listenerType)
13895
13896#endif // CATCH_CONFIG_DISABLE
13897
13898#endif // CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
13899
13900
13901#ifndef CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
13902#define CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
13903
13904
13905
13906namespace Catch {
13907
13908 class SonarQubeReporter final : public CumulativeReporterBase {
13909 public:
13910 SonarQubeReporter(ReporterConfig&& config)
13911 : CumulativeReporterBase(CATCH_MOVE(config))
13912 , xml(m_stream) {
13913 m_preferences.shouldRedirectStdOut = true;
13914 m_preferences.shouldReportAllAssertions = false;
13915 m_shouldStoreSuccesfulAssertions = false;
13916 }
13917
13918 static std::string getDescription() {
13919 using namespace std::string_literals;
13920 return "Reports test results in the Generic Test Data SonarQube XML format"s;
13921 }
13922
13923 void testRunStarting( TestRunInfo const& testRunInfo ) override;
13924
13925 void testRunEndedCumulative() override {
13926 writeRun( *m_testRun );
13927 xml.endElement();
13928 }
13929
13930 void writeRun( TestRunNode const& runNode );
13931
13932 void writeTestFile(StringRef filename, std::vector<TestCaseNode const*> const& testCaseNodes);
13933
13934 void writeTestCase(TestCaseNode const& testCaseNode);
13935
13936 void writeSection(std::string const& rootName, SectionNode const& sectionNode, bool okToFail);
13937
13938 void writeAssertions(SectionNode const& sectionNode, bool okToFail);
13939
13940 void writeAssertion(AssertionStats const& stats, bool okToFail);
13941
13942 private:
13943 XmlWriter xml;
13944 };
13945
13946
13947} // end namespace Catch
13948
13949#endif // CATCH_REPORTER_SONARQUBE_HPP_INCLUDED
13950
13951
13952#ifndef CATCH_REPORTER_TAP_HPP_INCLUDED
13953#define CATCH_REPORTER_TAP_HPP_INCLUDED
13954
13955
13956namespace Catch {
13957
13958 class TAPReporter final : public StreamingReporterBase {
13959 public:
13960 TAPReporter( ReporterConfig&& config ):
13961 StreamingReporterBase( CATCH_MOVE(config) ) {
13962 m_preferences.shouldReportAllAssertions = true;
13963 }
13964
13965 static std::string getDescription() {
13966 using namespace std::string_literals;
13967 return "Reports test results in TAP format, suitable for test harnesses"s;
13968 }
13969
13970 void testRunStarting( TestRunInfo const& testInfo ) override;
13971
13972 void noMatchingTestCases( StringRef unmatchedSpec ) override;
13973
13974 void assertionEnded(AssertionStats const& _assertionStats) override;
13975
13976 void testRunEnded(TestRunStats const& _testRunStats) override;
13977
13978 private:
13979 std::size_t counter = 0;
13980 };
13981
13982} // end namespace Catch
13983
13984#endif // CATCH_REPORTER_TAP_HPP_INCLUDED
13985
13986
13987#ifndef CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
13988#define CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
13989
13990
13991#include <cstring>
13992
13993#ifdef __clang__
13994# pragma clang diagnostic push
13995# pragma clang diagnostic ignored "-Wpadded"
13996#endif
13997
13998namespace Catch {
13999
14000 class TeamCityReporter final : public StreamingReporterBase {
14001 public:
14002 TeamCityReporter( ReporterConfig&& _config )
14003 : StreamingReporterBase( CATCH_MOVE(_config) )
14004 {
14005 m_preferences.shouldRedirectStdOut = true;
14006 }
14007
14008 ~TeamCityReporter() override;
14009
14010 static std::string getDescription() {
14011 using namespace std::string_literals;
14012 return "Reports test results as TeamCity service messages"s;
14013 }
14014
14015 void testRunStarting( TestRunInfo const& runInfo ) override;
14016 void testRunEnded( TestRunStats const& runStats ) override;
14017
14018
14019 void assertionEnded(AssertionStats const& assertionStats) override;
14020
14021 void sectionStarting(SectionInfo const& sectionInfo) override {
14022 m_headerPrintedForThisSection = false;
14023 StreamingReporterBase::sectionStarting( sectionInfo );
14024 }
14025
14026 void testCaseStarting(TestCaseInfo const& testInfo) override;
14027
14028 void testCaseEnded(TestCaseStats const& testCaseStats) override;
14029
14030 private:
14031 void printSectionHeader(std::ostream& os);
14032
14033 bool m_headerPrintedForThisSection = false;
14034 Timer m_testTimer;
14035 };
14036
14037} // end namespace Catch
14038
14039#ifdef __clang__
14040# pragma clang diagnostic pop
14041#endif
14042
14043#endif // CATCH_REPORTER_TEAMCITY_HPP_INCLUDED
14044
14045
14046#ifndef CATCH_REPORTER_XML_HPP_INCLUDED
14047#define CATCH_REPORTER_XML_HPP_INCLUDED
14048
14049
14050
14051
14052namespace Catch {
14053 class XmlReporter : public StreamingReporterBase {
14054 public:
14055 XmlReporter(ReporterConfig&& _config);
14056
14057 ~XmlReporter() override;
14058
14059 static std::string getDescription();
14060
14061 virtual std::string getStylesheetRef() const;
14062
14063 void writeSourceInfo(SourceLineInfo const& sourceInfo);
14064
14065 public: // StreamingReporterBase
14066
14067 void testRunStarting(TestRunInfo const& testInfo) override;
14068
14069 void testCaseStarting(TestCaseInfo const& testInfo) override;
14070
14071 void sectionStarting(SectionInfo const& sectionInfo) override;
14072
14073 void assertionStarting(AssertionInfo const&) override;
14074
14075 void assertionEnded(AssertionStats const& assertionStats) override;
14076
14077 void sectionEnded(SectionStats const& sectionStats) override;
14078
14079 void testCaseEnded(TestCaseStats const& testCaseStats) override;
14080
14081 void testRunEnded(TestRunStats const& testRunStats) override;
14082
14083 void benchmarkPreparing( StringRef name ) override;
14084 void benchmarkStarting(BenchmarkInfo const&) override;
14085 void benchmarkEnded(BenchmarkStats<> const&) override;
14086 void benchmarkFailed( StringRef error ) override;
14087
14088 void listReporters(std::vector<ReporterDescription> const& descriptions) override;
14089 void listListeners(std::vector<ListenerDescription> const& descriptions) override;
14090 void listTests(std::vector<TestCaseHandle> const& tests) override;
14091 void listTags(std::vector<TagInfo> const& tags) override;
14092
14093 private:
14094 Timer m_testCaseTimer;
14095 XmlWriter m_xml;
14096 int m_sectionDepth = 0;
14097 };
14098
14099} // end namespace Catch
14100
14101#endif // CATCH_REPORTER_XML_HPP_INCLUDED
14102
14103#endif // CATCH_REPORTERS_ALL_HPP_INCLUDED
14104
14105#endif // CATCH_ALL_HPP_INCLUDED
14106#endif // CATCH_AMALGAMATED_HPP_INCLUDED
diff --git a/unit_tests/deep_tests.cpp b/unit_tests/deep_tests.cpp
index c1708e1..60dadb7 100644
--- a/unit_tests/deep_tests.cpp
+++ b/unit_tests/deep_tests.cpp
@@ -8,94 +8,88 @@
8// ################################################################################################# 8// #################################################################################################
9// ################################################################################################# 9// #################################################################################################
10 10
11class DeepTests : public ::testing::Test 11TEST_CASE("deep_test")
12{ 12{
13 protected:
14 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 13 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
14 S.requireSuccess(
15 " lanes = require 'lanes'.configure()"
16 " fixture = require 'fixture'"
17 " deep_test = require 'deep_test'"
18 );
15 19
16 void SetUp() override 20 SECTION("garbage collection collects")
17 { 21 {
18 std::ignore = S.doString("lanes = require 'lanes'.configure()"); 22 S.requireSuccess("assert(true)");
19 std::ignore = S.doString("fixture = require 'fixture'"); 23 S.requireFailure("assert(false)");
20 std::ignore = S.doString("deep_test = require 'deep_test'"); 24 if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue
25 S.requireSuccess(
26 // create a deep userdata object without referencing it. First uservalue is a function, and should be called on __gc
27 " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)"
28 " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)"
29 " collectgarbage()" // and collect it
30 " assert(collected == 2)"
31 );
32 }
21 } 33 }
22};
23 34
24// ################################################################################################# 35 // ---------------------------------------------------------------------------------------------
25// #################################################################################################
26 36
27TEST_F(DeepTests, DeepIsCollected) 37 SECTION("reference counting")
28{ 38 {
29 ASSERT_EQ(S.doString("assert(true)"), LuaError::OK) << S; 39 S.requireSuccess(
30 ASSERT_NE(S.doString("assert(false)"), LuaError::OK) << S; 40 " d = deep_test.new_deep(1)" // create a deep userdata object
31 if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue 41 " d:set(42)" // set some value
32 ASSERT_EQ(S.doString( 42 " assert(d:refcount() == 1)"
33 // create a deep userdata object without referencing it. First uservalue is a function, and should be called on __gc 43 );
34 " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" 44 S.requireSuccess(
35 " deep_test.new_deep(1):setuv(1, function() collected = collected and collected + 1 or 1 end)" 45 " l = lanes.linda()"
36 " collectgarbage()" // and collect it 46 " b, s = l:set('k', d, d)" // store it twice in the linda
37 " assert(collected == 2)" 47 " assert(b == false and s == 'under')" // no waking, under capacity
38 ), LuaError::OK) << S; 48 " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice)
49 );
50 S.requireSuccess(
51 " n, d = l:get('k')" // pull it out of the linda
52 " assert(n == 1 and type(d) == 'userdata')" // got 1 item out of the linda
53 " assert(d:get() == 42 and d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice)
54 );
55 S.requireSuccess(
56 " l = nil"
57 " collectgarbage()" // clears the linda, removes its storage from the keeper
58 " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup
59 " assert(d:refcount() == 1)" // 1 ref here
60 );
61 if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue
62 S.requireSuccess(
63 " d:setuv(1, function() collected = collected and collected + 1 or 1 end)"
64 " d = nil" // clear last reference
65 " collectgarbage()" // force collection
66 " assert(collected == 1)" // we should see it
67 );
68 }
39 } 69 }
40}
41 70
42// ################################################################################################# 71 // ---------------------------------------------------------------------------------------------
43 72
44TEST_F(DeepTests, DeepRefcounting) 73 SECTION("collection from inside a Linda")
45{ 74 {
46 ASSERT_EQ(S.doString( 75 S.requireSuccess(
47 " d = deep_test.new_deep(1)" // create a deep userdata object 76 " d = deep_test.new_deep(1)" // create a deep userdata object
48 " d:set(42)" // set some value 77 " d:set(42)" // set some value
49 " assert(d:refcount() == 1)" 78 " assert(d:refcount() == 1)"
50 ), LuaError::OK) << S; 79 );
51 ASSERT_EQ(S.doString( 80 S.requireSuccess(
52 " l = lanes.linda()" 81 " l = lanes.linda()"
53 " b, s = l:set('k', d, d)" // store it twice in the linda 82 " b, s = l:set('k', d, d)" // store it twice in the linda
54 " assert(b == false and s == 'under')" // no waking, under capacity 83 " assert(b == false and s == 'under')" // no waking, under capacity
55 " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) 84 " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice)
56 ), LuaError::OK) << S; 85 );
57 ASSERT_EQ(S.doString( 86 S.requireSuccess(
58 " n, d = l:get('k')" // pull it out of the linda 87 " d = nil"
59 " assert(n == 1 and type(d) == 'userdata')" // got 1 item out of the linda 88 " collectgarbage()" // force collection
60 " assert(d:get() == 42 and d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice) 89 " l = nil"
61 ), LuaError::OK) << S; 90 " collectgarbage()" // clears the linda, removes its storage from the keeper
62 ASSERT_EQ(S.doString( 91 " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup
63 " l = nil" 92 " assert(deep_test.get_deep_count() == 0)"
64 " collectgarbage()" // clears the linda, removes its storage from the keeper 93 );
65 " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup
66 " assert(d:refcount() == 1)" // 1 ref here
67 ), LuaError::OK) << S;
68 if constexpr (LUA_VERSION_NUM >= 503) { // Lua < 5.3 only supports a table uservalue
69 ASSERT_EQ(S.doString(
70 " d:setuv(1, function() collected = collected and collected + 1 or 1 end)"
71 " d = nil" // clear last reference
72 " collectgarbage()" // force collection
73 " assert(collected == 1)" // we should see it
74 ), LuaError::OK) << S;
75 } 94 }
76}
77
78// #################################################################################################
79
80TEST_F(DeepTests, DeepCollectedFromInsideLinda)
81{
82 ASSERT_EQ(S.doString(
83 " d = deep_test.new_deep(1)" // create a deep userdata object
84 " d:set(42)" // set some value
85 " assert(d:refcount() == 1)"
86 ), LuaError::OK) << S;
87 ASSERT_EQ(S.doString(
88 " l = lanes.linda()"
89 " b, s = l:set('k', d, d)" // store it twice in the linda
90 " assert(b == false and s == 'under')" // no waking, under capacity
91 " assert(d:refcount() == 2)" // 1 ref here, 1 in the keeper (even if we sent it twice)
92 ), LuaError::OK) << S;
93 ASSERT_EQ(S.doString(
94 " d = nil"
95 " collectgarbage()" // force collection
96 " l = nil"
97 " collectgarbage()" // clears the linda, removes its storage from the keeper
98 " lanes.collectgarbage()" // collect garbage inside the keepers too, to finish cleanup
99 " assert(deep_test.get_deep_count() == 0)"
100 ), LuaError::OK) << S;
101} \ No newline at end of file 95} \ No newline at end of file
diff --git a/unit_tests/embedded_tests.cpp b/unit_tests/embedded_tests.cpp
index 03905d7..a6952b2 100644
--- a/unit_tests/embedded_tests.cpp
+++ b/unit_tests/embedded_tests.cpp
@@ -23,118 +23,114 @@ namespace
23 23
24// ################################################################################################# 24// #################################################################################################
25 25
26class EmbeddedTests : public ::testing::Test 26TEST_CASE("embedding")
27{ 27{
28 private:
29 HMODULE hCore{};
30
31 protected:
32 LuaState S{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; 28 LuaState S{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } };
33 lua_CFunction lanes_register{};
34 29
35 void SetUp() override 30 HMODULE hCore = LoadLibraryW(L"lanes\\core");
36 { 31 if (!hCore) {
37 hCore = LoadLibraryW(L"lanes\\core"); 32 throw std::logic_error("Could not load lanes.core");
38 if (!hCore) { 33 }
39 throw std::logic_error("Could not load lanes.core"); 34 luaopen_lanes_embedded_t const _p_luaopen_lanes_embedded{ reinterpret_cast<luaopen_lanes_embedded_t>(GetProcAddress(hCore, "luaopen_lanes_embedded")) };
40 } 35 if (!_p_luaopen_lanes_embedded) {
41 luaopen_lanes_embedded_t const _p_luaopen_lanes_embedded{ reinterpret_cast<luaopen_lanes_embedded_t>(GetProcAddress(hCore, "luaopen_lanes_embedded")) }; 36 throw std::logic_error("Could not bind luaopen_lanes_embedded");
42 if (!_p_luaopen_lanes_embedded) { 37 }
43 throw std::logic_error("Could not bind luaopen_lanes_embedded");
44 }
45 38
46 lanes_register = reinterpret_cast<lua_CFunction>(GetProcAddress(hCore, "lanes_register")); 39 lua_CFunction lanes_register = reinterpret_cast<lua_CFunction>(GetProcAddress(hCore, "lanes_register"));
47 if (!lanes_register) { 40 if (!lanes_register) {
48 throw std::logic_error("Could not bind lanes_register"); 41 throw std::logic_error("Could not bind lanes_register");
49 } 42 }
50 // need base to make lanes happy 43 // need base to make lanes happy
51 luaL_requiref(S, LUA_GNAME, luaopen_base, 1); 44 luaL_requiref(S, LUA_GNAME, luaopen_base, 1);
52 lua_pop(S, 1); 45 lua_pop(S, 1);
53 S.stackCheck(0); 46 S.stackCheck(0);
54 47
55 // need package to be able to require lanes 48 // need package to be able to require lanes
56 luaL_requiref(S, LUA_LOADLIBNAME, luaopen_package, 1); 49 luaL_requiref(S, LUA_LOADLIBNAME, luaopen_package, 1);
57 lua_pop(S, 1); 50 lua_pop(S, 1);
58 S.stackCheck(0); 51 S.stackCheck(0);
59 52
60 // need table to make lanes happy 53 // need table to make lanes happy
61 luaL_requiref(S, LUA_TABLIBNAME, luaopen_table, 1); 54 luaL_requiref(S, LUA_TABLIBNAME, luaopen_table, 1);
62 lua_pop(S, 1); 55 lua_pop(S, 1);
63 S.stackCheck(0); 56 S.stackCheck(0);
64 57
65 // need string to make lanes happy 58 // need string to make lanes happy
66 luaL_requiref(S, LUA_STRLIBNAME, luaopen_string, 1); 59 luaL_requiref(S, LUA_STRLIBNAME, luaopen_string, 1);
67 lua_pop(S, 1); 60 lua_pop(S, 1);
68 S.stackCheck(0); 61 S.stackCheck(0);
69 62
70 _p_luaopen_lanes_embedded(S, local::load_lanes_lua); // S: lanes 63 auto load_lanes_lua = +[](lua_State* const L_) {
71 lua_pop(S, 1); 64 if (0 == luaL_dofile(L_, "lanes.lua")) {
72 S.stackCheck(0); 65 return 1;
73 } 66 } else {
67 return 0;
68 }
69 };
70
71 _p_luaopen_lanes_embedded(S, local::load_lanes_lua); // S: lanes
72 lua_pop(S, 1);
73 S.stackCheck(0);
74
75 // ---------------------------------------------------------------------------------------------
74 76
75 void TearDown() override 77 SECTION("single state")
76 { 78 {
77 // close state manually before we unload lanes.core 79 // this sends data in a linda. current contents:
78 S.close(); 80 // key: short string
79 FreeLibrary(hCore); 81 // values:
82 // bool
83 // integer
84 // number
85 // long string
86 // table with array and hash parts
87 // function with an upvalue
88 std::string_view const _script{
89 " local lanes = require 'lanes'.configure{with_timers = false}"
90 " local l = lanes.linda'gleh'"
91 " local upvalue = 'oeauaoeuoeuaoeuaoeujaoefubycfjbycfybcfjybcfjybcfjbcf'"
92 " local upvalued = function()"
93 " return upvalue"
94 " end"
95 " local t = setmetatable({ true, true, true, a = true}, {__index = rawget })"
96 " l:set('yo', true, 10, 100.0, upvalue, t, upvalued)" // put a breakpoint in linda_set to have some data to explore with the NATVIS
97 " return 'SUCCESS'"
98 };
99 S.requireReturnedString(_script, "SUCCESS");
80 } 100 }
81};
82 101
83TEST_F(EmbeddedTests, SingleState) 102 // ---------------------------------------------------------------------------------------------
84{
85 // this sends data in a linda. current contents:
86 // key: short string
87 // values:
88 // bool
89 // integer
90 // number
91 // long string
92 // table with array and hash parts
93 // function with an upvalue
94 std::string_view const script{
95 " local lanes = require 'lanes'.configure{with_timers = false}"
96 " local l = lanes.linda'gleh'"
97 " local upvalue = 'oeauaoeuoeuaoeuaoeujaoefubycfjbycfybcfjybcfjybcfjbcf'"
98 " local upvalued = function()"
99 " return upvalue"
100 " end"
101 " local t = setmetatable({ true, true, true, a = true}, {__index = rawget })"
102 " l:set('yo', true, 10, 100.0, upvalue, t, upvalued)" // put a breakpoint in linda_set to have some data to explore with the NATVIS
103 " return 'SUCCESS'"
104 };
105 std::string_view result = S.doStringAndRet(script);
106 ASSERT_EQ(result, "SUCCESS");
107}
108 103
109// ################################################################################################# 104 SECTION("manual registration")
105 {
106 S.requireSuccess("require 'lanes'.configure{with_timers = false}");
110 107
111TEST_F(EmbeddedTests, ManualRegister) 108 // require 'io' library after Lanes is initialized:
112{ 109 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1);
113 ASSERT_EQ(S.doString("require 'lanes'.configure{with_timers = false}"), LuaError::OK) << S; 110 lua_pop(S, 1);
114 lua_pop(S, 1); 111 S.stackCheck(0);
115 112
116 // require 'io' library after Lanes is initialized: 113 // try to send io.open into a linda
117 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1); 114 std::string_view const _script{
118 lua_pop(S, 1); 115 " local lanes = require 'lanes'.configure{with_timers = false}"
119 S.stackCheck(0); 116 " local l = lanes.linda'gleh'"
117 " l:set('yo', io.open)"
118 " return 'SUCCESS'"
119 };
120 S.requireNotReturnedString(_script, "SUCCESS");
121
122 // try again after manual registration
123 lua_pushcfunction(S, lanes_register); // S: lanes_register
124 luaG_pushstring(S, LUA_IOLIBNAME); // S: lanes_register "io"
125 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1); // S: lanes_register "io" io
126 lua_call(S, 2, 0); // S:
127 S.stackCheck(0);
128 S.requireReturnedString(_script, "SUCCESS");
129 }
120 130
121 // try to send io.open into a linda 131 // ---------------------------------------------------------------------------------------------
122 std::string_view const script{ 132
123 "local lanes = require 'lanes'.configure{with_timers = false}" 133 // close state manually before we unload lanes.core
124 "local l = lanes.linda'gleh'" 134 S.close();
125 "l:set('yo', io.open)" 135 FreeLibrary(hCore);
126 "return 'SUCCESS'"
127 };
128 std::string_view const result1{ S.doStringAndRet(script) };
129 ASSERT_NE(result1, "SUCCESS") << S; // S: "msg"
130 lua_pop(S, 1); // S:
131
132 // try again after manual registration
133 lua_pushcfunction(S, lanes_register); // S: lanes_register
134 luaG_pushstring(S, LUA_IOLIBNAME); // S: lanes_register "io"
135 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1); // S: lanes_register "io" io
136 lua_call(S, 2, 0); // S:
137 S.stackCheck(0);
138 std::string_view const result2{ S.doStringAndRet(script) };
139 ASSERT_EQ(result2, "SUCCESS") << S;
140} 136}
diff --git a/unit_tests/init_and_shutdown.cpp b/unit_tests/init_and_shutdown.cpp
index d45b52f..83c0350 100644
--- a/unit_tests/init_and_shutdown.cpp
+++ b/unit_tests/init_and_shutdown.cpp
@@ -3,14 +3,12 @@
3 3
4// ################################################################################################# 4// #################################################################################################
5 5
6TEST(Require, MissingBaseLibraries) 6TEST_CASE("require 'lanes'")
7{ 7{
8 LuaState L{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; 8 LuaState L{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } };
9 9
10 // no base library loaded means no print() 10 // no base library loaded means no print()
11 EXPECT_NE(L.doString("print('hello')"), LuaError::OK); 11 L.requireFailure("print('hello')");
12 L.stackCheck(1);
13 lua_pop(L, 1);
14 12
15 // need require() to require lanes 13 // need require() to require lanes
16 luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 0); 14 luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 0);
@@ -18,9 +16,7 @@ TEST(Require, MissingBaseLibraries)
18 L.stackCheck(0); 16 L.stackCheck(0);
19 17
20 // no base library loaded means lanes should issue an error 18 // no base library loaded means lanes should issue an error
21 EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); 19 L.requireFailure("require 'lanes'");
22 lua_pop(L, 1);
23 L.stackCheck(0);
24 20
25 // need base to make lanes happy 21 // need base to make lanes happy
26 luaL_requiref(L, LUA_GNAME, luaopen_base, 1); 22 luaL_requiref(L, LUA_GNAME, luaopen_base, 1);
@@ -28,9 +24,7 @@ TEST(Require, MissingBaseLibraries)
28 L.stackCheck(0); 24 L.stackCheck(0);
29 25
30 // no table library loaded means lanes should issue an error 26 // no table library loaded means lanes should issue an error
31 EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); 27 L.requireFailure("require 'lanes'");
32 L.stackCheck(1);
33 lua_pop(L, 1);
34 28
35 // need table to make lanes happy 29 // need table to make lanes happy
36 luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1); 30 luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1);
@@ -38,9 +32,7 @@ TEST(Require, MissingBaseLibraries)
38 L.stackCheck(0); 32 L.stackCheck(0);
39 33
40 // no string library loaded means lanes should issue an error 34 // no string library loaded means lanes should issue an error
41 EXPECT_NE(L.doString("require 'lanes'"), LuaError::OK); 35 L.requireFailure("require 'lanes'");
42 lua_pop(L, 1);
43 L.stackCheck(0);
44 36
45 // need string to make lanes happy 37 // need string to make lanes happy
46 luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1); 38 luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1);
@@ -50,7 +42,7 @@ TEST(Require, MissingBaseLibraries)
50 // all required libraries are here: we should be happy 42 // all required libraries are here: we should be happy
51 // that's only the case for Lua > 5.1 though, because the latter can't require() a module after a previously failed attempt (like we just did) 43 // that's only the case for Lua > 5.1 though, because the latter can't require() a module after a previously failed attempt (like we just did)
52 if constexpr (LUA_VERSION_NUM > 501) { 44 if constexpr (LUA_VERSION_NUM > 501) {
53 ASSERT_EQ(L.doString("require 'lanes'"), LuaError::OK); 45 L.requireSuccess("require 'lanes'");
54 } else { 46 } else {
55 // so let's do a fresh attempt in a virgin state where we have the 3 base libraries we need (plus 'package' to be able to require it of course) 47 // so let's do a fresh attempt in a virgin state where we have the 3 base libraries we need (plus 'package' to be able to require it of course)
56 LuaState L51{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; 48 LuaState L51{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } };
@@ -59,625 +51,653 @@ TEST(Require, MissingBaseLibraries)
59 luaL_requiref(L51, LUA_TABLIBNAME, luaopen_table, 1); 51 luaL_requiref(L51, LUA_TABLIBNAME, luaopen_table, 1);
60 luaL_requiref(L51, LUA_STRLIBNAME, luaopen_string, 1); 52 luaL_requiref(L51, LUA_STRLIBNAME, luaopen_string, 1);
61 lua_settop(L51, 0); 53 lua_settop(L51, 0);
62 ASSERT_EQ(L51.doString("require 'lanes'"), LuaError::OK); 54 L51.requireSuccess("require 'lanes'");
63 } 55 }
64} 56}
65 57
66class Configure : public ::testing::Test
67{
68 protected:
69 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
70};
71
72// ################################################################################################# 58// #################################################################################################
73// ################################################################################################# 59// #################################################################################################
74// allocator should be "protected", a C function returning a suitable userdata, or nil 60// allocator should be "protected", a C function returning a suitable userdata, or nil
75 61
76TEST_F(Configure, AllocatorFalse) 62TEST_CASE("lanes.configure")
77{ 63{
78 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = false}"), LuaError::OK); 64 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
79}
80 65
81// ################################################################################################# 66 // ---------------------------------------------------------------------------------------------
82 67
83TEST_F(Configure, AllocatorTrue) 68 SECTION("allocator", "[allocator]")
84{ 69 {
85 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = true}"), LuaError::OK); 70 SECTION("allocator = false")
86} 71 {
72 L.requireFailure("require 'lanes'.configure{allocator = false}");
73 }
87 74
88// ################################################################################################# 75 // -----------------------------------------------------------------------------------------
89 76
90TEST_F(Configure, AllocatorNumber) 77 SECTION("allocator = true")
91{ 78 {
92 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 33}"), LuaError::OK); 79 L.requireFailure("require 'lanes'.configure{allocator = true}");
93} 80 }
94 81
95// ################################################################################################# 82 // -----------------------------------------------------------------------------------------
96 83
97TEST_F(Configure, AllocatorTable) 84 SECTION("allocator = <number>")
98{ 85 {
99 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = {}}"), LuaError::OK); 86 L.requireFailure("require 'lanes'.configure{allocator = 33}");
100} 87 }
101 88
102// ################################################################################################# 89 // -----------------------------------------------------------------------------------------
103 90
104TEST_F(Configure, AllocatorLuaFunction) 91 SECTION("allocator = <table>")
105{ 92 {
106 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}"), LuaError::OK); 93 L.requireFailure("require 'lanes'.configure{allocator = {}}");
107} 94 }
108 95
109// ################################################################################################# 96 // -----------------------------------------------------------------------------------------
110 97
111TEST_F(Configure, AllocatorBadCFunction) 98 SECTION("allocator = <Lua function>")
112{ 99 {
113 // a C function that doesn't return what we expect should cause an error too 100 L.requireFailure("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}");
114 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = print}"), LuaError::OK); 101 }
115}
116 102
117// ################################################################################################# 103 // -----------------------------------------------------------------------------------------
118 104
119TEST_F(Configure, AllocatorTypo) 105 SECTION("allocator = <bad C function>")
120{ 106 {
121 // oops, a typo 107 // a C function that doesn't return what we expect should cause an error too
122 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = 'Protected'}"), LuaError::OK); 108 L.requireFailure("require 'lanes'.configure{allocator = print}");
123} 109 }
124 110
125// ################################################################################################# 111 // -----------------------------------------------------------------------------------------
126 112
127TEST_F(Configure, AllocatorProtected) 113 SECTION("allocator = <string with a typo>")
128{ 114 {
129 // no typo, should work 115 // oops, a typo
130 EXPECT_EQ(L.doString("require 'lanes'.configure{allocator = 'protected'}"), LuaError::OK); 116 L.requireFailure("require 'lanes'.configure{allocator = 'Protected'}");
131} 117 }
132 118
133// ################################################################################################# 119 // -----------------------------------------------------------------------------------------
134 120
135TEST_F(Configure, AllocatorCustomOk) 121 SECTION("allocator = 'protected'")
136{ 122 {
137 // a function that provides what we expect is fine 123 // no typo, should work
138 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { 124 L.requireSuccess("require 'lanes'.configure{allocator = 'protected'}");
139 lanes::AllocatorDefinition* const _def{ new (L_) lanes::AllocatorDefinition{} }; 125 }
140 _def->initFrom(L_);
141 return 1;
142 };
143 lua_pushcfunction(L, _provideAllocator);
144 lua_setglobal(L, "ProvideAllocator");
145 EXPECT_EQ(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK);
146}
147 126
148// ################################################################################################# 127 // -----------------------------------------------------------------------------------------
149 128
150TEST_F(Configure, AllocatorCustomWrongResultType) 129 SECTION("allocator = <good custom C allocator>")
151{ 130 {
152 // a function that provides something that is definitely not an AllocatorDefinition, should cause an error 131 // a function that provides what we expect is fine
153 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { 132 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) {
154 lua_newtable(L_); 133 lanes::AllocatorDefinition* const _def{ new (L_) lanes::AllocatorDefinition{} };
155 return 1; 134 _def->initFrom(L_);
156 }; 135 return 1;
157 lua_pushcfunction(L, _provideAllocator); 136 };
158 lua_setglobal(L, "ProvideAllocator"); 137 lua_pushcfunction(L, _provideAllocator);
159 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); 138 lua_setglobal(L, "ProvideAllocator");
160} 139 L.requireSuccess("require 'lanes'.configure{allocator = ProvideAllocator}");
140 }
161 141
162// ################################################################################################# 142 // -----------------------------------------------------------------------------------------
163 143
164TEST_F(Configure, AllocatorCustomSignatureMismatch) 144 SECTION("allocator not returning an AllocatorDefinition")
165{ 145 {
166 // a function that provides something that is too small to contain an AllocatorDefinition, should cause an error 146 // a function that provides something that is definitely not an AllocatorDefinition, should cause an error
167 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { 147 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) {
168 // create a full userdata that is too small (it only contains enough to store a version tag, but not the rest 148 lua_newtable(L_);
169 auto* const _duck{ static_cast<lanes::AllocatorDefinition::version_t*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition::version_t))) }; 149 return 1;
170 *_duck = 666777; 150 };
171 return 1; 151 lua_pushcfunction(L, _provideAllocator);
172 }; 152 lua_setglobal(L, "ProvideAllocator");
173 lua_pushcfunction(L, _provideAllocator); 153 L.requireFailure("require 'lanes'.configure{allocator = ProvideAllocator}");
174 lua_setglobal(L, "ProvideAllocator"); 154 }
175 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK);
176}
177 155
178// ################################################################################################# 156 // -----------------------------------------------------------------------------------------
179 157
180TEST_F(Configure, AllocatorCustomSizeMismatch) 158 SECTION("allocator returning an AllocatorDefinition with the wrong signature")
181{ 159 {
182 // a function that provides something that attempts to pass as an AllocatorDefinition, but is not, should cause an error 160 // a function that provides something that is too small to contain an AllocatorDefinition, should cause an error
183 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { 161 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) {
184 // create a full userdata of the correct size, but of course the contents don't match 162 // create a full userdata that is too small (it only contains enough to store a version tag, but not the rest
185 int* const _duck{ static_cast<int*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition))) }; 163 auto* const _duck{ static_cast<lanes::AllocatorDefinition::version_t*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition::version_t))) };
186 _duck[0] = 666; 164 *_duck = 666777;
187 _duck[1] = 777; 165 return 1;
188 return 1; 166 };
189 }; 167 lua_pushcfunction(L, _provideAllocator);
190 lua_pushcfunction(L, _provideAllocator); 168 lua_setglobal(L, "ProvideAllocator");
191 lua_setglobal(L, "ProvideAllocator"); 169 L.requireFailure("require 'lanes'.configure{allocator = ProvideAllocator}");
192 EXPECT_NE(L.doString("require 'lanes'.configure{allocator = ProvideAllocator}"), LuaError::OK); 170 }
193}
194 171
195// ################################################################################################# 172 // -----------------------------------------------------------------------------------------
196// #################################################################################################
197// internal_allocator should be a string, "libc"/"allocator"
198 173
199TEST_F(Configure, InternalAllocatorFalse) 174 SECTION("allocator returning something too small to be a valid AllocatorDefinition")
200{ 175 {
201 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = false}"), LuaError::OK); 176 // a function that provides something that attempts to pass as an AllocatorDefinition, but is not, should cause an error
202} 177 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) {
178 // create a full userdata of the correct size, but of course the contents don't match
179 int* const _duck{ static_cast<int*>(lua_newuserdata(L_, sizeof(lanes::AllocatorDefinition))) };
180 _duck[0] = 666;
181 _duck[1] = 777;
182 return 1;
183 };
184 lua_pushcfunction(L, _provideAllocator);
185 lua_setglobal(L, "ProvideAllocator");
186 L.requireFailure("require 'lanes'.configure{allocator = ProvideAllocator}");
187 }
188 }
203 189
204// ################################################################################################# 190 // ---------------------------------------------------------------------------------------------
191 // internal_allocator should be a string, "libc"/"allocator"
205 192
206TEST_F(Configure, InternalAllocatorTrue) 193 SECTION("[internal_allocator")
207{ 194 {
208 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = true}"), LuaError::OK); 195 SECTION("internal_allocator = false")
209} 196 {
197 L.requireFailure("require 'lanes'.configure{internal_allocator = false}");
198 }
210 199
211// ################################################################################################# 200 // -----------------------------------------------------------------------------------------
212 201
213TEST_F(Configure, InternalAllocatorTable) 202 SECTION("internal_allocator = true")
214{ 203 {
215 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = {}}"), LuaError::OK); 204 L.requireFailure("require 'lanes'.configure{internal_allocator = true}");
216} 205 }
217 206
218// ################################################################################################# 207 // -----------------------------------------------------------------------------------------
219 208
220TEST_F(Configure, InternalAllocatorFunction) 209 SECTION("internal_allocator = <table>")
221{ 210 {
222 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = function() end}"), LuaError::OK); 211 L.requireFailure("require 'lanes'.configure{internal_allocator = {}}");
223} 212 }
224 213
225// ################################################################################################# 214 // -----------------------------------------------------------------------------------------
226 215
227TEST_F(Configure, InternalAllocatorString) 216 SECTION("internal_allocator = <Lua function>")
228{ 217 {
229 EXPECT_NE(L.doString("require 'lanes'.configure{internal_allocator = 'gluh'}"), LuaError::OK); 218 L.requireFailure("require 'lanes'.configure{internal_allocator = function() end}");
230} 219 }
231 220
232// ################################################################################################# 221 // -----------------------------------------------------------------------------------------
233 222
234TEST_F(Configure, InternalAllocatorLibc) 223 SECTION("internal_allocator = <bad string>")
235{ 224 {
236 EXPECT_EQ(L.doString("require 'lanes'.configure{internal_allocator = 'libc'}"), LuaError::OK); 225 L.requireFailure("require 'lanes'.configure{internal_allocator = 'gluh'}");
237} 226 }
238 227
239// ################################################################################################# 228 // -----------------------------------------------------------------------------------------
240 229
241TEST_F(Configure, InternalAllocatorAllocator) 230 SECTION("internal_allocator = 'libc'")
242{ 231 {
243 EXPECT_EQ(L.doString("require 'lanes'.configure{internal_allocator = 'allocator'}"), LuaError::OK); 232 L.requireSuccess("require 'lanes'.configure{internal_allocator = 'libc'}");
244} 233 }
245 234
246// ################################################################################################# 235 // -----------------------------------------------------------------------------------------
247// #################################################################################################
248// keepers_gc_threshold should be a number in [0, 100]
249 236
250TEST_F(Configure, KeepersGcThresholdTable) 237 SECTION("internal_allocator = 'allocator'")
251{ 238 {
252 EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = {}}"), LuaError::OK); 239 L.requireSuccess("require 'lanes'.configure{internal_allocator = 'allocator'}");
253} 240 }
241 }
254 242
255// ################################################################################################# 243 // ---------------------------------------------------------------------------------------------
244 // keepers_gc_threshold should be a number in [0, 100]
256 245
257TEST_F(Configure, KeepersGcThresholdString) 246 SECTION("keepers_gc_threshold")
258{ 247 {
259 EXPECT_NE(L.doString("require 'lanes'.configure{keepers_gc_threshold = 'gluh'}"), LuaError::OK); 248 SECTION("keepers_gc_threshold = <table>")
260} 249 {
250 L.requireFailure("require 'lanes'.configure{keepers_gc_threshold = {}}");
251 }
261 252
262// ################################################################################################# 253 // -----------------------------------------------------------------------------------------
263 254
264TEST_F(Configure, KeepersGcThresholdNegative) 255 SECTION("keepers_gc_threshold = <string>")
265{ 256 {
266 EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = -1}"), LuaError::OK); 257 L.requireFailure("require 'lanes'.configure{keepers_gc_threshold = 'gluh'}");
267} 258 }
268 259
269// ################################################################################################# 260 // -----------------------------------------------------------------------------------------
270 261
271TEST_F(Configure, KeepersGcThresholdZero) 262 SECTION("keepers_gc_threshold = -1")
272{ 263 {
273 EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = 0}"), LuaError::OK); 264 L.requireSuccess("require 'lanes'.configure{keepers_gc_threshold = -1}");
274} 265 }
275 266
276// ################################################################################################# 267 // -----------------------------------------------------------------------------------------
277 268
278TEST_F(Configure, KeepersGcThresholdHundred) 269 SECTION("keepers_gc_threshold = 0")
279{ 270 {
280 EXPECT_EQ(L.doString("require 'lanes'.configure{keepers_gc_threshold = 100}"), LuaError::OK); 271 L.requireSuccess("require 'lanes'.configure{keepers_gc_threshold = 0}");
281} 272 }
282 273
283// ################################################################################################# 274 // -----------------------------------------------------------------------------------------
284// #################################################################################################
285// nb_user_keepers should be a number in [0, 100]
286 275
287TEST_F(Configure, NbUserKeepersTable) 276 SECTION("keepers_gc_threshold = 100")
288{ 277 {
289 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = {}}"), LuaError::OK); 278 L.requireSuccess("require 'lanes'.configure{keepers_gc_threshold = 100}");
290} 279 }
280 }
291 281
292// ################################################################################################# 282 // ---------------------------------------------------------------------------------------------
283 // nb_user_keepers should be a number in [0, 100]
293 284
294TEST_F(Configure, NbUserKeepersString) 285 SECTION("nb_user_keepers")
295{ 286 {
296 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = 'gluh'}"), LuaError::OK); 287 SECTION("nb_user_keepers = <table>")
297} 288 {
289 L.requireFailure("require 'lanes'.configure{nb_user_keepers = {}}");
290 }
298 291
299// ################################################################################################# 292 // -----------------------------------------------------------------------------------------
300 293
301TEST_F(Configure, NbUserKeepersNegative) 294 SECTION("nb_user_keepers = <string>")
302{ 295 {
303 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = -1}"), LuaError::OK); 296 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 'gluh'}");
304} 297 }
305 298
306// ################################################################################################# 299 // -----------------------------------------------------------------------------------------
307 300
308TEST_F(Configure, NbUserKeepersZero) 301 SECTION("nb_user_keepers = -1")
309{ 302 {
310 EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 0}"), LuaError::OK); 303 L.requireFailure("require 'lanes'.configure{nb_user_keepers = -1}");
311} 304 }
312 305
313// ################################################################################################# 306 // -----------------------------------------------------------------------------------------
314 307
315TEST_F(Configure, NbUserKeepersHundred) 308 SECTION("nb_user_keepers = 0")
316{ 309 {
317 EXPECT_EQ(L.doString("require 'lanes'.configure{nb_user_keepers = 100}"), LuaError::OK); 310 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 0}");
318} 311 }
319 312
320// ################################################################################################# 313 // -----------------------------------------------------------------------------------------
321 314
322TEST_F(Configure, NbUserKeepersHundredAndOne) 315 SECTION("nb_user_keepers = 100")
323{ 316 {
324 EXPECT_NE(L.doString("require 'lanes'.configure{nb_user_keepers = 101}"), LuaError::OK); 317 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 100}");
325} 318 }
326 319
327// ################################################################################################# 320 // -----------------------------------------------------------------------------------------
328// #################################################################################################
329// on_state_create should be a function, either C or Lua, without upvalues
330 321
331TEST_F(Configure, OnStateCreateTable) 322 SECTION("nb_user_keepers = 101")
332{ 323 {
333 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = {}}"), LuaError::OK); 324 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 101}");
334} 325 }
326 }
335 327
336// ################################################################################################# 328 // ---------------------------------------------------------------------------------------------
329 // on_state_create should be a function, either C or Lua, without upvalues
337 330
338TEST_F(Configure, OnStateCreateString) 331 SECTION("on_state_create")
339{ 332 {
340 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 'gluh'}"), LuaError::OK); 333 SECTION("on_state_create = <table>")
341} 334 {
335 L.requireFailure("require 'lanes'.configure{on_state_create = {}}");
336 }
342 337
343// ################################################################################################# 338 // -----------------------------------------------------------------------------------------
344 339
345TEST_F(Configure, OnStateCreateNumber) 340 SECTION("on_state_create = <string>")
346{ 341 {
347 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = 1}"), LuaError::OK); 342 L.requireFailure("require 'lanes'.configure{on_state_create = 'gluh'}");
348} 343 }
349 344
350// ################################################################################################# 345 // -----------------------------------------------------------------------------------------
351 346
352TEST_F(Configure, OnStateCreateFalse) 347 SECTION("on_state_create = <number>")
353{ 348 {
354 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = false}"), LuaError::OK); 349 L.requireFailure("require 'lanes'.configure{on_state_create = 1}");
355} 350 }
356 351
357// ################################################################################################# 352 // -----------------------------------------------------------------------------------------
358 353
359TEST_F(Configure, OnStateCreateTrue) 354 SECTION("on_state_create = false")
360{ 355 {
361 EXPECT_NE(L.doString("require 'lanes'.configure{on_state_create = true}"), LuaError::OK); 356 L.requireFailure("require 'lanes'.configure{on_state_create = false}");
362} 357 }
363 358
364// ################################################################################################# 359 // -----------------------------------------------------------------------------------------
365 360
366TEST_F(Configure, OnStateCreateUpvaluedFunction) 361 SECTION("on_state_create = true")
367{ 362 {
368 // on_state_create isn't called inside a Keeper state if it's a Lua function (which is good as print() doesn't exist there!) 363 L.requireFailure("require 'lanes'.configure{on_state_create = true}");
369 EXPECT_EQ(L.doString("local print = print; require 'lanes'.configure{on_state_create = function() print 'hello' end}"), LuaError::OK); 364 }
370}
371 365
372// ################################################################################################# 366 // -----------------------------------------------------------------------------------------
373 367
374TEST_F(Configure, OnStateCreateCFunction) 368 SECTION("on_state_create = <Lua function>")
375{ 369 {
376 // funnily enough, in Lua 5.3, print() uses global tostring(), that doesn't exist in a keeper since we didn't open libs -> "attempt to call a nil value" 370 // on_state_create isn't called inside a Keeper state if it's a Lua function (which is good as print() doesn't exist there!)
377 // conclusion, don't use print() as a fake on_state_create() callback! 371 L.requireSuccess("local print = print; require 'lanes'.configure{on_state_create = function() print 'hello' end}");
378 // assert() should be fine since we pass a non-false argument to on_state_create 372 }
379 EXPECT_EQ(L.doString("require 'lanes'.configure{on_state_create = assert}"), LuaError::OK);
380}
381 373
382// ################################################################################################# 374 // -----------------------------------------------------------------------------------------
383// #################################################################################################
384// shutdown_timeout should be a number in [0,3600]
385 375
386TEST_F(Configure, ShutdownTimeoutTable) 376 SECTION("on_state_create = <C function>")
387{ 377 {
388 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = {}}"), LuaError::OK); 378 // funnily enough, in Lua 5.3, print() uses global tostring(), that doesn't exist in a keeper since we didn't open libs -> "attempt to call a nil value"
389} 379 // conclusion, don't use print() as a fake on_state_create() callback!
380 // assert() should be fine since we pass a non-false argument to on_state_create
381 L.requireSuccess("require 'lanes'.configure{on_state_create = assert}");
382 }
383 }
390 384
391// ################################################################################################# 385 // ---------------------------------------------------------------------------------------------
386 // shutdown_timeout should be a number in [0,3600]
392 387
393TEST_F(Configure, ShutdownTimeoutString) 388 SECTION("shutdown_timeout")
394{ 389 {
395 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = 'gluh'}"), LuaError::OK); 390 SECTION("shutdown_timeout = <table>")
396} 391 {
392 L.requireFailure("require 'lanes'.configure{shutdown_timeout = {}}");
393 }
397 394
398// ################################################################################################# 395 // -----------------------------------------------------------------------------------------
399 396
400TEST_F(Configure, ShutdownTimeoutNegative) 397 SECTION("shutdown_timeout = <string>")
401{ 398 {
402 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = -0.001}"), LuaError::OK); 399 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 'gluh'}");
403} 400 }
404 401
405// ################################################################################################# 402 // -----------------------------------------------------------------------------------------
406 403
407TEST_F(Configure, ShutdownTimeoutZero) 404 SECTION("shutdown_timeout = <negative number>")
408{ 405 {
409 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 0}"), LuaError::OK); 406 L.requireFailure("require 'lanes'.configure{shutdown_timeout = -0.001}");
410} 407 }
411 408
412// ################################################################################################# 409 // -----------------------------------------------------------------------------------------
413 410
414TEST_F(Configure, ShutdownTimeoutOne) 411 SECTION("shutdown_timeout = 0")
415{ 412 {
416 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 1}"), LuaError::OK); 413 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 0}");
417} 414 }
418 415
419// ################################################################################################# 416 // -----------------------------------------------------------------------------------------
420 417
421TEST_F(Configure, ShutdownTimeoutHour) 418 SECTION("shutdown_timeout = 1s")
422{ 419 {
423 EXPECT_EQ(L.doString("require 'lanes'.configure{shutdown_timeout = 3600}"), LuaError::OK); 420 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 1}");
424} 421 }
425 422
426// ################################################################################################# 423 // -----------------------------------------------------------------------------------------
427 424
428TEST_F(Configure, ShutdownTimeoutTooLong) 425 SECTION("shutdown_timeout = 3600s")
429{ 426 {
430 EXPECT_NE(L.doString("require 'lanes'.configure{shutdown_timeout = 3600.001}"), LuaError::OK); 427 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 3600}");
431} 428 }
432 429
433// ################################################################################################# 430 // -----------------------------------------------------------------------------------------
434// #################################################################################################
435// strip_functions should be a boolean
436 431
437TEST_F(Configure, StripFunctionsTable) 432 SECTION("shutdown_timeout = <too long>")
438{ 433 {
439 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = {}}"), LuaError::OK); 434 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 3600.001}");
440} 435 }
436 }
441 437
442// ################################################################################################# 438 // ---------------------------------------------------------------------------------------------
439 // strip_functions should be a boolean
443 440
444TEST_F(Configure, StripFunctionsString) 441 SECTION("strip_functions")
445{ 442 {
446 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 'gluh'}"), LuaError::OK); 443 SECTION("strip_functions = <table>")
447} 444 {
445 L.requireFailure("require 'lanes'.configure{strip_functions = {}}");
446 }
448 447
449// ################################################################################################# 448 // -----------------------------------------------------------------------------------------
450 449
451TEST_F(Configure, StripFunctionsNumber) 450 SECTION("strip_functions = <string>")
452{ 451 {
453 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = 1}"), LuaError::OK); 452 L.requireFailure("require 'lanes'.configure{strip_functions = 'gluh'}");
454} 453 }
455 454
456// ################################################################################################# 455 // -----------------------------------------------------------------------------------------
457 456
458TEST_F(Configure, StripFunctionsFunction) 457 SECTION("strip_functions = <number>")
459{ 458 {
460 EXPECT_NE(L.doString("require 'lanes'.configure{strip_functions = print}"), LuaError::OK); 459 L.requireFailure("require 'lanes'.configure{strip_functions = 1}");
461} 460 }
462 461
463// ################################################################################################# 462 // -----------------------------------------------------------------------------------------
464 463
465TEST_F(Configure, StripFunctionsFalse) 464 SECTION("strip_functions = <C function>")
466{ 465 {
467 EXPECT_EQ(L.doString("require 'lanes'.configure{strip_functions = false}"), LuaError::OK); 466 L.requireFailure("require 'lanes'.configure{strip_functions = print}");
468} 467 }
469 468
470// ################################################################################################# 469 // -----------------------------------------------------------------------------------------
471 470
472TEST_F(Configure, StripFunctionsTrue) 471 SECTION("strip_functions = false")
473{ 472 {
474 EXPECT_EQ(L.doString("require 'lanes'.configure{strip_functions = true}"), LuaError::OK); 473 L.requireSuccess("require 'lanes'.configure{strip_functions = false}");
475} 474 }
476 475
477// ################################################################################################# 476 // -----------------------------------------------------------------------------------------
478// #################################################################################################
479// track_lanes should be a boolean
480 477
481TEST_F(Configure, TrackLanesTable) 478 SECTION("strip_functions = true")
482{ 479 {
483 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = {}}"), LuaError::OK); 480 L.requireSuccess("require 'lanes'.configure{strip_functions = true}");
484} 481 }
482 }
485 483
486// ################################################################################################# 484 // ---------------------------------------------------------------------------------------------
485 // track_lanes should be a boolean
487 486
488TEST_F(Configure, TrackLanesString) 487 SECTION("track_lanes")
489{ 488 {
490 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 'gluh'}"), LuaError::OK); 489 SECTION("track_lanes = <table>")
491} 490 {
491 L.requireFailure("require 'lanes'.configure{track_lanes = {}}");
492 }
492 493
493// ################################################################################################# 494 // -----------------------------------------------------------------------------------------
494 495
495TEST_F(Configure, TrackLanesNumber) 496 SECTION("track_lanes = <string>")
496{ 497 {
497 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = 1}"), LuaError::OK); 498 L.requireFailure("require 'lanes'.configure{track_lanes = 'gluh'}");
498} 499 }
499 500
500// ################################################################################################# 501 // -----------------------------------------------------------------------------------------
501 502
502TEST_F(Configure, TrackLanesFunction) 503 SECTION("track_lanes = <number>")
503{ 504 {
504 EXPECT_NE(L.doString("require 'lanes'.configure{track_lanes = print}"), LuaError::OK); 505 L.requireFailure("require 'lanes'.configure{track_lanes = 1}");
505} 506 }
506 507
507// ################################################################################################# 508 // -----------------------------------------------------------------------------------------
508 509
509TEST_F(Configure, TrackLanesFalse) 510 SECTION("track_lanes = <C function>")
510{ 511 {
511 EXPECT_EQ(L.doString("require 'lanes'.configure{track_lanes = false}"), LuaError::OK); 512 L.requireFailure("require 'lanes'.configure{track_lanes = print}");
512} 513 }
513 514
514// ################################################################################################# 515 // -----------------------------------------------------------------------------------------
515 516
516TEST_F(Configure, TrackLanesTrue) 517 SECTION("track_lanes = false")
517{ 518 {
518 EXPECT_EQ(L.doString("require 'lanes'.configure{track_lanes = true}"), LuaError::OK); 519 L.requireSuccess("require 'lanes'.configure{track_lanes = false}");
519} 520 }
520 521
521// ################################################################################################# 522 // -----------------------------------------------------------------------------------------
522// #################################################################################################
523// verbose_errors should be a boolean
524 523
525TEST_F(Configure, VerboseErrorsTable) 524 SECTION("track_lanes = true")
526{ 525 {
527 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = {}}"), LuaError::OK); 526 L.requireSuccess("require 'lanes'.configure{track_lanes = true}");
528} 527 }
528 }
529 529
530// ################################################################################################# 530 // ---------------------------------------------------------------------------------------------
531 // verbose_errors should be a boolean
531 532
532TEST_F(Configure, VerboseErrorsString) 533 SECTION("verbose_errors")
533{ 534 {
534 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 'gluh'}"), LuaError::OK); 535 SECTION("verbose_errors = <table>")
535} 536 {
537 L.requireFailure("require 'lanes'.configure{verbose_errors = {}}");
538 }
536 539
537// ################################################################################################# 540 // -----------------------------------------------------------------------------------------
538 541
539TEST_F(Configure, VerboseErrorsNumber) 542 SECTION("verbose_errors = <string>")
540{ 543 {
541 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = 1}"), LuaError::OK); 544 L.requireFailure("require 'lanes'.configure{verbose_errors = 'gluh'}");
542} 545 }
543 546
544// ################################################################################################# 547 // -----------------------------------------------------------------------------------------
545 548
546TEST_F(Configure, VerboseErrorsFunction) 549 SECTION("verbose_errors = <number>")
547{ 550 {
548 EXPECT_NE(L.doString("require 'lanes'.configure{verbose_errors = print}"), LuaError::OK); 551 L.requireFailure("require 'lanes'.configure{verbose_errors = 1}");
549} 552 }
550 553
551// ################################################################################################# 554 // -----------------------------------------------------------------------------------------
552 555
553TEST_F(Configure, VerboseErrorsFalse) 556 SECTION("verbose_errors = <C function>")
554{ 557 {
555 EXPECT_EQ(L.doString("require 'lanes'.configure{verbose_errors = false}"), LuaError::OK); 558 L.requireFailure("require 'lanes'.configure{verbose_errors = print}");
556} 559 }
557 560
558// ################################################################################################# 561 // -----------------------------------------------------------------------------------------
559 562
560TEST_F(Configure, VerboseErrorsTrue) 563 SECTION("verbose_errors = false")
561{ 564 {
562 EXPECT_EQ(L.doString("require 'lanes'.configure{verbose_errors = true}"), LuaError::OK); 565 L.requireSuccess("require 'lanes'.configure{verbose_errors = false}");
563} 566 }
564 567
565// ################################################################################################# 568 // -----------------------------------------------------------------------------------------
566// #################################################################################################
567// with_timers should be a boolean
568 569
569TEST_F(Configure, WithTimersTable) 570 SECTION("verbose_errors = true")
570{ 571 {
571 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = {}}"), LuaError::OK); 572 L.requireSuccess("require 'lanes'.configure{verbose_errors = true}");
572} 573 }
574 }
573 575
574// ################################################################################################# 576 // ---------------------------------------------------------------------------------------------
577 // with_timers should be a boolean
575 578
576TEST_F(Configure, WithTimersString) 579 SECTION("with_timers")
577{ 580 {
578 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 'gluh'}"), LuaError::OK); 581 SECTION("with_timers = <table>")
579} 582 {
583 L.requireFailure("require 'lanes'.configure{with_timers = {}}");
584 }
580 585
581// ################################################################################################# 586 // -----------------------------------------------------------------------------------------
582 587
583TEST_F(Configure, WithTimersNumber) 588 SECTION("with_timers = <string>")
584{ 589 {
585 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = 1}"), LuaError::OK); 590 L.requireFailure("require 'lanes'.configure{with_timers = 'gluh'}");
586} 591 }
587 592
588// ################################################################################################# 593 // -----------------------------------------------------------------------------------------
589 594
590TEST_F(Configure, WithTimersFunction) 595 SECTION("with_timers = <number>")
591{ 596 {
592 EXPECT_NE(L.doString("require 'lanes'.configure{with_timers = print}"), LuaError::OK); 597 L.requireFailure("require 'lanes'.configure{with_timers = 1}");
593} 598 }
594 599
595// ################################################################################################# 600 // -----------------------------------------------------------------------------------------
596 601
597TEST_F(Configure, WithTimersFalse) 602 SECTION("with_timers = <C function>")
598{ 603 {
599 EXPECT_EQ(L.doString("require 'lanes'.configure{with_timers = false}"), LuaError::OK); 604 L.requireFailure("require 'lanes'.configure{with_timers = print}");
600} 605 }
601 606
602// ################################################################################################# 607 // -----------------------------------------------------------------------------------------
603 608
604TEST_F(Configure, WithTimersTrue) 609 SECTION("with_timers = false")
605{ 610 {
606 EXPECT_EQ(L.doString("require 'lanes'.configure{with_timers = true}"), LuaError::OK); 611 L.requireSuccess("require 'lanes'.configure{with_timers = false}");
607} 612 }
608 613
609// ################################################################################################# 614 // -----------------------------------------------------------------------------------------
610// #################################################################################################
611// any unknown setting should be rejected
612 615
613TEST_F(Configure, UnknownSettingTable) 616 SECTION("with_timers = true")
614{ 617 {
615 EXPECT_NE(L.doString("require 'lanes'.configure{[{}] = {}}"), LuaError::OK); 618 L.requireSuccess("require 'lanes'.configure{with_timers = true}");
616} 619 }
620 }
617 621
618// ################################################################################################# 622 // ---------------------------------------------------------------------------------------------
623 // any unknown setting should be rejected
619 624
620TEST_F(Configure, UnknownSettingBool) 625 SECTION("unknown_setting")
621{ 626 {
622 EXPECT_NE(L.doString("require 'lanes'.configure{[true] = 'gluh'}"), LuaError::OK); 627 SECTION("table setting")
623} 628 {
629 L.requireFailure("require 'lanes'.configure{[{}] = {}}");
630 }
624 631
625// ################################################################################################# 632 // -----------------------------------------------------------------------------------------
626 633
627TEST_F(Configure, UnknownSettingFunction) 634 SECTION("boolean setting")
628{ 635 {
629 EXPECT_NE(L.doString("require 'lanes'.configure{[function() end] = 1}"), LuaError::OK); 636 L.requireFailure("require 'lanes'.configure{[true] = 'gluh'}");
630} 637 }
631 638
632// ################################################################################################# 639 // -----------------------------------------------------------------------------------------
633 640
634TEST_F(Configure, UnknownSettingNumber) 641 SECTION("function setting")
635{ 642 {
636 EXPECT_NE(L.doString("require 'lanes'.configure{[1] = function() end}"), LuaError::OK); 643 L.requireFailure("require 'lanes'.configure{[function() end] = 1}");
637} 644 }
638 645
639// ################################################################################################# 646 // -----------------------------------------------------------------------------------------
640 647
641TEST_F(Configure, UnknownSettingString) 648 SECTION("number setting")
642{ 649 {
643 EXPECT_NE(L.doString("require 'lanes'.configure{['gluh'] = false}"), LuaError::OK); 650 L.requireFailure("require 'lanes'.configure{[1] = function() end}");
651 }
652
653 // -----------------------------------------------------------------------------------------
654
655 SECTION("unknown string setting")
656 {
657 L.requireFailure("require 'lanes'.configure{['gluh'] = false}");
658 }
659 }
644} 660}
645 661
646// ################################################################################################# 662// #################################################################################################
647// ################################################################################################# 663// #################################################################################################
648 664
649TEST(Lanes, Finally) 665TEST_CASE("lanes.finally")
650{ 666{
667 SECTION("no fixture")
651 { 668 {
652 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 669 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
653 // we need Lanes to be up. Since we run several 'scripts', we store it as a global 670 // we need Lanes to be up. Since we run several 'scripts', we store it as a global
654 EXPECT_EQ(S.doString("lanes = require 'lanes'"), LuaError::OK) << S; 671 S.requireSuccess("lanes = require 'lanes'");
655 // we can set a function 672 // we can set a function
656 EXPECT_EQ(S.doString("lanes.finally(function() end)"), LuaError::OK) << S; 673 S.requireSuccess("lanes.finally(function() end)");
657 // we can clear it 674 // we can clear it
658 EXPECT_EQ(S.doString("lanes.finally(nil)"), LuaError::OK) << S; 675 S.requireSuccess("lanes.finally(nil)");
659 // we can set a new one 676 // we can set a new one
660 EXPECT_EQ(S.doString("lanes.finally(function() end)"), LuaError::OK) << S; 677 S.requireSuccess("lanes.finally(function() end)");
661 // we can replace an existing function 678 // we can replace an existing function
662 EXPECT_EQ(S.doString("lanes.finally(error)"), LuaError::OK) << S; 679 S.requireSuccess("lanes.finally(error)");
663 // even if the finalizer throws a Lua error, it shouldn't crash anything 680 // even if the finalizer throws a Lua error, it shouldn't crash anything
664 ASSERT_NO_FATAL_FAILURE(S.close()); 681 REQUIRE_NOTHROW(S.close()); // TODO: use lua_atpanic to catch errors during close()
665 ASSERT_EQ(S.finalizerWasCalled, false); 682 REQUIRE_FALSE(S.finalizerWasCalled);
666 } 683 }
667 684
685 // ---------------------------------------------------------------------------------------------
686
687 SECTION("with fixture")
668 { 688 {
669 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 689 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
670 690
671 // we need Lanes to be up. Since we run several 'scripts', we store it as a global 691 // we need Lanes to be up. Since we run several 'scripts', we store it as a global
672 EXPECT_EQ(S.doString("lanes = require 'lanes'"), LuaError::OK) << S; 692 S.requireSuccess("lanes = require 'lanes'");
673 // works because we have package.preload.fixture = luaopen_fixture 693 // works because we have package.preload.fixture = luaopen_fixture
674 EXPECT_EQ(S.doString("fixture = require 'fixture'"), LuaError::OK) << S; 694 S.requireSuccess("fixture = require 'fixture'");
675 // set our detectable finalizer 695 // set our detectable finalizer
676 EXPECT_EQ(S.doString("lanes.finally(fixture.throwing_finalizer)"), LuaError::OK) << S; 696 S.requireSuccess("lanes.finally(fixture.throwing_finalizer)");
677 // even if the finalizer can request a C++ exception, it shouldn't do it just now since we have no dangling lane 697 // even if the finalizer can request a C++ exception, it shouldn't do it just now since we have no dangling lane
678 ASSERT_NO_THROW(S.close()) << S; 698 REQUIRE_NOTHROW(S.close());
679 // the finalizer should be called 699 // the finalizer should be called
680 ASSERT_EQ(S.finalizerWasCalled, true); 700 REQUIRE(S.finalizerWasCalled);
681 } 701 }
682} 702}
683 703
@@ -697,97 +717,92 @@ namespace
697 } // namespace local 717 } // namespace local
698} 718}
699 719
700class OnStateCreate : public ::testing::Test
701{
702 protected:
703 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
704
705 void SetUp() override
706 {
707 local::OnStateCreateCallsCount.store(0, std::memory_order_relaxed);
708 }
709
710 void TearDown() override
711 {
712 local::OnStateCreateCallsCount.store(0, std::memory_order_relaxed);
713 }
714};
715
716// ################################################################################################# 720// #################################################################################################
717 721
718TEST_F(OnStateCreate, CalledInKeepers) 722TEST_CASE("on_state_create setting")
719{ 723{
720 // _G.on_state_create = on_state_create; 724 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
721 lua_pushcfunction(S, local::on_state_create);
722 lua_setglobal(S, "on_state_create");
723 ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create, nb_user_keepers = 3}"), LuaError::OK) << S;
724 ASSERT_EQ(local::OnStateCreateCallsCount.load(std::memory_order_relaxed), 4) << "on_state_create should have been called once in each Keeper state";
725}
726 725
727// ################################################################################################# 726 local::OnStateCreateCallsCount.store(0, std::memory_order_relaxed);
727 auto on_state_create = +[](lua_State* const L_) {
728 local::OnStateCreateCallsCount.fetch_add(1, std::memory_order_relaxed);
729 return 0;
730 };
728 731
729TEST_F(OnStateCreate, CalledInLane)
730{
731 // _G.on_state_create = on_state_create;
732 lua_pushcfunction(S, local::on_state_create);
733 lua_setglobal(S, "on_state_create");
734 ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create, with_timers = true}"), LuaError::OK) << S;
735 ASSERT_EQ(local::OnStateCreateCallsCount.load(std::memory_order_relaxed), 2) << "on_state_create should have been called in the Keeper state and the timer lane";
736}
737 732
738// ################################################################################################# 733 SECTION("on_state_create called in Keeper states")
734 {
735 // _G.on_state_create = on_state_create;
736 lua_pushcfunction(S, local::on_state_create);
737 lua_setglobal(S, "on_state_create");
738 S.requireSuccess("lanes = require 'lanes'.configure{on_state_create = on_state_create, nb_user_keepers = 3}");
739 REQUIRE(local::OnStateCreateCallsCount.load(std::memory_order_relaxed) == 4);
740 }
739 741
740TEST_F(OnStateCreate, CanPackagePreload) 742 // ---------------------------------------------------------------------------------------------
741{
742 // a C function for which we can test it was called
743 static bool _doStuffWasCalled{};
744 static auto _doStuff = +[](lua_State* const L_) {
745 _doStuffWasCalled = true;
746 return 0;
747 };
748 743
749 // a module that exports the above function 744 SECTION("on_state_create called in lane")
750 static auto _luaopen_Stuff = +[](lua_State* const L_) { 745 {
751 lua_newtable(L_); // t 746 // _G.on_state_create = on_state_create;
752 lua_pushstring(L_, "DoStuffInC"); // t "DoStuffInC" 747 lua_pushcfunction(S, local::on_state_create);
753 lua_pushcfunction(L_, _doStuff); // t "DoStuffInC" _doStuff 748 lua_setglobal(S, "on_state_create");
754 lua_settable(L_, -3); // t 749 S.requireSuccess("lanes = require 'lanes'.configure{on_state_create = on_state_create, with_timers = true}");
755 return 1; 750 REQUIRE(local::OnStateCreateCallsCount.load(std::memory_order_relaxed) == 2);
756 }; 751 }
757 752
758 // a function that installs the module loader function in package.preload 753 // ---------------------------------------------------------------------------------------------
759 auto _on_state_create = [](lua_State* const L_) {
760 754
761 lua_getglobal(L_, "package"); // package 755 SECTION("on_state_create changes package.preload")
762 if (lua_istable(L_, -1)) { 756 {
763 lua_getfield(L_, -1, "preload"); // package package.preload 757 // a C function for which we can test it was called
758 static bool _doStuffWasCalled{};
759 static auto _doStuff = +[](lua_State* const L_) {
760 _doStuffWasCalled = true;
761 return 0;
762 };
763
764 // a module that exports the above function
765 static auto _luaopen_Stuff = +[](lua_State* const L_) {
766 lua_newtable(L_); // t
767 lua_pushstring(L_, "DoStuffInC"); // t "DoStuffInC"
768 lua_pushcfunction(L_, _doStuff); // t "DoStuffInC" _doStuff
769 lua_settable(L_, -3); // t
770 return 1;
771 };
772
773 // a function that installs the module loader function in package.preload
774 auto _on_state_create = [](lua_State* const L_) {
775 lua_getglobal(L_, "package"); // package
764 if (lua_istable(L_, -1)) { 776 if (lua_istable(L_, -1)) {
765 lua_pushcfunction(L_, _luaopen_Stuff); // package package.preload luaopen_Stuff 777 lua_getfield(L_, -1, "preload"); // package package.preload
766 lua_setfield(L_, -2, "Stuff"); // package package.preload 778 if (lua_istable(L_, -1)) {
779 lua_pushcfunction(L_, _luaopen_Stuff); // package package.preload luaopen_Stuff
780 lua_setfield(L_, -2, "Stuff"); // package package.preload
781 }
782 lua_pop(L_, 1); // package
767 } 783 }
768 lua_pop(L_, 1); // package 784 lua_pop(L_, 1); //
769 }
770 lua_pop(L_, 1); //
771 785
772 return 0; 786 return 0;
773 }; 787 };
774 788
775 // _G.on_state_create = on_state_create; 789 // _G.on_state_create = on_state_create;
776 lua_pushcfunction(S, _on_state_create); 790 lua_pushcfunction(S, _on_state_create);
777 lua_setglobal(S, "on_state_create"); 791 lua_setglobal(S, "on_state_create");
778 792
779 ASSERT_EQ(S.doString("lanes = require 'lanes'.configure{on_state_create = on_state_create}"), LuaError::OK) << S; 793 S.requireSuccess("lanes = require 'lanes'.configure{on_state_create = on_state_create}");
780 794
781 // launch a Lane that requires the module. It should succeed because _on_state_create was called and made it possible 795 // launch a Lane that requires the module. It should succeed because _on_state_create was called and made it possible
782 std::string_view const _script{ 796 std::string_view const _script{
783 " f = lanes.gen('*'," 797 " f = lanes.gen('*',"
784 " function()" 798 " function()"
785 " local Stuff = require ('Stuff')" 799 " local Stuff = require ('Stuff')"
786 " Stuff.DoStuffInC()" 800 " Stuff.DoStuffInC()"
787 " return true" 801 " return true"
788 " end)" 802 " end)"
789 " f():join()" // start the lane and block until it terminates 803 " f():join()" // start the lane and block until it terminates
790 }; 804 };
791 ASSERT_EQ(S.doString(_script), LuaError::OK) << S; 805 S.requireSuccess(_script);
792 ASSERT_TRUE(_doStuffWasCalled); 806 REQUIRE(_doStuffWasCalled);
793} 807 }
808} \ No newline at end of file
diff --git a/unit_tests/lane_tests.cpp b/unit_tests/lane_tests.cpp
index 8b22fcd..7f5f112 100644
--- a/unit_tests/lane_tests.cpp
+++ b/unit_tests/lane_tests.cpp
@@ -4,257 +4,271 @@
4// ################################################################################################# 4// #################################################################################################
5// ################################################################################################# 5// #################################################################################################
6 6
7class LaneTests : public ::testing::Test 7TEST_CASE("lanes.gen")
8{ 8{
9 protected:
10 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 9 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
10 S.requireSuccess("lanes = require 'lanes'.configure()");
11 11
12 void SetUp() override 12 // ---------------------------------------------------------------------------------------------
13 {
14 std::ignore = S.doString("lanes = require 'lanes'.configure()");
15 }
16};
17
18// #################################################################################################
19 13
20TEST_F(LaneTests, GeneratorCreation) 14 SECTION("argument checks")
21{ 15 {
22 // no parameter is bad 16 // no parameter is bad
23 EXPECT_NE(S.doString("lanes.gen()"), LuaError::OK); 17 S.requireFailure("lanes.gen()");
24 18
25 // minimal generator needs a function 19 // minimal generator needs a function
26 EXPECT_EQ(S.doString("lanes.gen(function() end)"), LuaError::OK) << S; 20 S.requireSuccess("lanes.gen(function() end)");
27 21
28 // acceptable parameters for the generator are strings, tables, nil, followed by the function body 22 // acceptable parameters for the generator are strings, tables, nil, followed by the function body
29 EXPECT_EQ(S.doString("lanes.gen(nil, function() end)"), LuaError::OK) << S; 23 S.requireSuccess("lanes.gen(nil, function() end)");
30 EXPECT_EQ(S.doString("lanes.gen('', function() end)"), LuaError::OK) << S; 24 S.requireSuccess("lanes.gen('', function() end)");
31 EXPECT_EQ(S.doString("lanes.gen({}, function() end)"), LuaError::OK) << S; 25 S.requireSuccess("lanes.gen({}, function() end)");
32 EXPECT_EQ(S.doString("lanes.gen('', {}, function() end)"), LuaError::OK) << S; 26 S.requireSuccess("lanes.gen('', {}, function() end)");
33 EXPECT_EQ(S.doString("lanes.gen({}, '', function() end)"), LuaError::OK) << S; 27 S.requireSuccess("lanes.gen({}, '', function() end)");
34 EXPECT_EQ(S.doString("lanes.gen('', '', function() end)"), LuaError::OK) << S; 28 S.requireSuccess("lanes.gen('', '', function() end)");
35 EXPECT_EQ(S.doString("lanes.gen({}, {}, function() end)"), LuaError::OK) << S; 29 S.requireSuccess("lanes.gen({}, {}, function() end)");
36 30
37 // anything different should fail: booleans, numbers, any userdata 31 // anything different should fail: booleans, numbers, any userdata
38 EXPECT_NE(S.doString("lanes.gen(false, function() end)"), LuaError::OK); 32 S.requireFailure("lanes.gen(false, function() end)");
39 EXPECT_NE(S.doString("lanes.gen(true, function() end)"), LuaError::OK); 33 S.requireFailure("lanes.gen(true, function() end)");
40 EXPECT_NE(S.doString("lanes.gen(42, function() end)"), LuaError::OK); 34 S.requireFailure("lanes.gen(42, function() end)");
41 EXPECT_NE(S.doString("lanes.gen(io.stdin, function() end)"), LuaError::OK); 35 S.requireFailure("lanes.gen(io.stdin, function() end)");
42 EXPECT_NE(S.doString("lanes.gen(lanes.linda(), function() end)"), LuaError::OK); 36 S.requireFailure("lanes.gen(lanes.linda(), function() end)");
43 EXPECT_NE(S.doString("lanes.gen(lanes.linda():deep(), function() end)"), LuaError::OK); 37 S.requireFailure("lanes.gen(lanes.linda():deep(), function() end)");
44 38
45 // even if parameter types are correct, the function must come last 39 // even if parameter types are correct, the function must come last
46 EXPECT_NE(S.doString("lanes.gen(function() end, '')"), LuaError::OK); 40 S.requireFailure("lanes.gen(function() end, '')");
47 41
48 // the strings should only list "known base libraries", in any order, or "*" 42 // the strings should only list "known base libraries", in any order, or "*"
49 // if the particular Lua flavor we build for doesn't support them, they raise an error unless postfixed by '?' 43 // if the particular Lua flavor we build for doesn't support them, they raise an error unless postfixed by '?'
50 EXPECT_EQ(S.doString("lanes.gen('base', function() end)"), LuaError::OK) << S; 44 S.requireSuccess("lanes.gen('base', function() end)");
51 45
52 // bit, ffi, jit are LuaJIT-specific 46 // bit, ffi, jit are LuaJIT-specific
53#if LUAJIT_FLAVOR() == 0 47#if LUAJIT_FLAVOR() == 0
54 EXPECT_NE(S.doString("lanes.gen('bit,ffi,jit', function() end)"), LuaError::OK); 48 S.requireFailure("lanes.gen('bit,ffi,jit', function() end)");
55 EXPECT_EQ(S.doString("lanes.gen('bit?,ffi?,jit?', function() end)"), LuaError::OK) << S; 49 S.requireSuccess("lanes.gen('bit?,ffi?,jit?', function() end)");
56#endif // LUAJIT_FLAVOR() 50#endif // LUAJIT_FLAVOR()
57 51
58 // bit32 library existed only in Lua 5.2, there is still a loader that will raise an error in Lua 5.3 52 // bit32 library existed only in Lua 5.2, there is still a loader that will raise an error in Lua 5.3
59#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 53#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
60 EXPECT_EQ(S.doString("lanes.gen('bit32', function() end)"), LuaError::OK) << S; 54 S.requireSuccess("lanes.gen('bit32', function() end)");
61#else // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 55#else // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
62 EXPECT_NE(S.doString("lanes.gen('bit32', function() end)"), LuaError::OK); 56 S.requireFailure("lanes.gen('bit32', function() end)");
63 EXPECT_EQ(S.doString("lanes.gen('bit32?', function() end)"), LuaError::OK) << S; 57 S.requireSuccess("lanes.gen('bit32?', function() end)");
64#endif // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 58#endif // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
65 59
66 // coroutine library appeared with Lua 5.2 60 // coroutine library appeared with Lua 5.2
67#if LUA_VERSION_NUM == 501 61#if LUA_VERSION_NUM == 501
68 EXPECT_NE(S.doString("lanes.gen('coroutine', function() end)"), LuaError::OK); 62 S.requireFailure("lanes.gen('coroutine', function() end)");
69 EXPECT_EQ(S.doString("lanes.gen('coroutine?', function() end)"), LuaError::OK) << S; 63 S.requireSuccess("lanes.gen('coroutine?', function() end)");
70#endif // LUA_VERSION_NUM == 501 64#endif // LUA_VERSION_NUM == 501
71 65
72 EXPECT_EQ(S.doString("lanes.gen('debug', function() end)"), LuaError::OK) << S; 66 S.requireSuccess("lanes.gen('debug', function() end)");
73 EXPECT_EQ(S.doString("lanes.gen('io', function() end)"), LuaError::OK) << S; 67 S.requireSuccess("lanes.gen('io', function() end)");
74 EXPECT_EQ(S.doString("lanes.gen('math', function() end)"), LuaError::OK) << S; 68 S.requireSuccess("lanes.gen('math', function() end)");
75 EXPECT_EQ(S.doString("lanes.gen('os', function() end)"), LuaError::OK) << S; 69 S.requireSuccess("lanes.gen('os', function() end)");
76 EXPECT_EQ(S.doString("lanes.gen('package', function() end)"), LuaError::OK) << S; 70 S.requireSuccess("lanes.gen('package', function() end)");
77 EXPECT_EQ(S.doString("lanes.gen('string', function() end)"), LuaError::OK) << S; 71 S.requireSuccess("lanes.gen('string', function() end)");
78 EXPECT_EQ(S.doString("lanes.gen('table', function() end)"), LuaError::OK) << S; 72 S.requireSuccess("lanes.gen('table', function() end)");
79 73
80 // utf8 library appeared with Lua 5.3 74 // utf8 library appeared with Lua 5.3
81#if LUA_VERSION_NUM < 503 75#if LUA_VERSION_NUM < 503
82 EXPECT_NE(S.doString("lanes.gen('utf8', function() end)"), LuaError::OK); 76 S.requireFailure("lanes.gen('utf8', function() end)");
83 EXPECT_EQ(S.doString("lanes.gen('utf8?', function() end)"), LuaError::OK) << S; 77 S.requireSuccess("lanes.gen('utf8?', function() end)");
84#endif // LUA_VERSION_NUM < 503 78#endif // LUA_VERSION_NUM < 503
85 79
86 EXPECT_EQ(S.doString("lanes.gen('lanes.core', function() end)"), LuaError::OK) << S; 80 S.requireSuccess("lanes.gen('lanes.core', function() end)");
87 // "*" repeated or combined with anything else is forbidden 81 // "*" repeated or combined with anything else is forbidden
88 EXPECT_NE(S.doString("lanes.gen('*', '*', function() end)"), LuaError::OK); 82 S.requireFailure("lanes.gen('*', '*', function() end)");
89 EXPECT_NE(S.doString("lanes.gen('base', '*', function() end)"), LuaError::OK); 83 S.requireFailure("lanes.gen('base', '*', function() end)");
90 // unknown names are forbidden 84 // unknown names are forbidden
91 EXPECT_NE(S.doString("lanes.gen('Base', function() end)"), LuaError::OK); 85 S.requireFailure("lanes.gen('Base', function() end)");
92 // repeating the same library more than once is forbidden 86 // repeating the same library more than once is forbidden
93 EXPECT_NE(S.doString("lanes.gen('base,base', function() end)"), LuaError::OK); 87 S.requireFailure("lanes.gen('base,base', function() end)");
94} 88 }
95 89
96// ################################################################################################# 90 // ---------------------------------------------------------------------------------------------
97 91
98TEST_F(LaneTests, UncooperativeShutdown) 92 SECTION("lanes.finally") // TODO: move this section somewhere else, in a dedicated finally TEST_CASE
99{ 93 {
100 // prepare a callback for lanes.finally() 94 // prepare a callback for lanes.finally()
101 static bool _wasCalled{}; 95 static bool _wasCalled{};
102 static bool _allLanesTerminated{}; 96 static bool _allLanesTerminated{};
103 auto _finallyCB{ +[](lua_State* const L_) { _wasCalled = true; _allLanesTerminated = lua_toboolean(L_, 1); return 0; } }; 97 auto _finallyCB{ +[](lua_State* const L_) { _wasCalled = true; _allLanesTerminated = lua_toboolean(L_, 1); return 0; } };
104 lua_pushcfunction(S, _finallyCB); 98 lua_pushcfunction(S, _finallyCB);
105 lua_setglobal(S, "finallyCB"); 99 lua_setglobal(S, "finallyCB");
106 // start a lane that lasts a long time 100 // start a lane that lasts a long time
107 std::string_view const _script{ 101 std::string_view const _script{
108 " lanes.finally(finallyCB)" 102 " lanes.finally(finallyCB)"
109 " g = lanes.gen('*'," 103 " g = lanes.gen('*',"
110 " {name = 'auto'}," 104 " {name = 'auto'},"
111 " function()" 105 " function()"
112 " for i = 1,1e37 do end" // no cooperative cancellation checks here! 106 " for i = 1,1e37 do end" // no cooperative cancellation checks here!
113 " end)" 107 " end)"
114 " g()" 108 " g()"
115 }; 109 };
116 ASSERT_EQ(S.doString(_script), LuaError::OK) << S; 110 S.requireSuccess(_script);
117 // close the state before the lane ends. 111 // close the state before the lane ends.
118 // since we don't wait at all, it is possible that the OS thread for the lane hasn't even started at that point 112 // since we don't wait at all, it is possible that the OS thread for the lane hasn't even started at that point
119 S.close(); 113 S.close();
120 // the finally handler should have been called, and told all lanes are stopped 114 // the finally handler should have been called, and told all lanes are stopped
121 ASSERT_EQ(_wasCalled, true) << S; 115 REQUIRE(_wasCalled);
122 ASSERT_EQ(_allLanesTerminated, true) << S; 116 REQUIRE(_allLanesTerminated);
123} 117 }
124 118
125// ################################################################################################# 119 // ---------------------------------------------------------------------------------------------
126 120
127TEST_F(LaneTests, DefaultThreadNameIsUnnamed) 121 SECTION("default thread name is '<unnamed>'")
128{ 122 {
129 std::string_view const _script{ 123 std::string_view const _script{
130 " g = lanes.gen('*'," 124 " g = lanes.gen('*',"
131 " function()" 125 " function()"
132 " return lane_threadname()" 126 " return lane_threadname()"
133 " end)" 127 " end)"
134 " h = g()" 128 " h = g()"
135 " local tn = h[1]" 129 " local tn = h[1]"
136 " assert(tn == h:get_threadname())" 130 " assert(tn == h:get_threadname())"
137 " return tn" 131 " assert(tn == '<unnamed>')"
138 }; 132 };
139 ASSERT_EQ(S.doStringAndRet(_script), "<unnamed>") << S; 133 S.requireSuccess(_script);
140} 134 }
141 135
142// ################################################################################################# 136 // ---------------------------------------------------------------------------------------------
143 137
144TEST_F(LaneTests, UserThreadNameFromGenerator) 138 SECTION("set thread name from generator settings")
145{ 139 {
146 std::string_view const _script{ 140 std::string_view const _script{
147 " g = lanes.gen('*'," 141 " g = lanes.gen('*',"
148 " { name = 'user name'}," 142 " { name = 'user name'},"
149 " function()" 143 " function()"
150 " return lane_threadname()" 144 " return lane_threadname()"
151 " end)" 145 " end)"
152 " h = g()" 146 " h = g()"
153 " local tn = h[1]" 147 " local tn = h[1]"
154 " assert(tn == h:get_threadname())" 148 " assert(tn == h:get_threadname())"
155 " return tn" 149 " assert(tn == 'user name')"
156 }; 150 };
157 ASSERT_EQ(S.doStringAndRet(_script), "user name") << S; 151 S.requireSuccess(_script);
158} 152 }
159 153
160// ################################################################################################# 154 // ---------------------------------------------------------------------------------------------
161 155
162TEST_F(LaneTests, UserThreadNameFromInside) 156 SECTION("set thread name from lane body")
163{ 157 {
164 std::string_view const _script{ 158 std::string_view const _script{
165 " g = lanes.gen('*'," 159 " g = lanes.gen('*',"
166 " function()" 160 " function()"
167 " lane_threadname('user name')" 161 " lane_threadname('user name')"
168 " return true" 162 " return true"
169 " end)" 163 " end)"
170 " h = g()" 164 " h = g()"
171 " h:join()" 165 " h:join()"
172 " return h:get_threadname()" 166 " assert(h:get_threadname() == 'user name')"
173 }; 167 };
174 ASSERT_EQ(S.doStringAndRet(_script), "user name") << S; 168 S.requireSuccess(_script);
169 }
175} 170}
176 171
177// ################################################################################################# 172// #################################################################################################
178// ################################################################################################# 173// #################################################################################################
179 174
180class LaneCancel : public ::testing::Test 175TEST_CASE("lane:cancel")
181{ 176{
182 protected:
183 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 177 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
184 178
185 void SetUp() override 179 // need the timers so that there is a lane running on which we can operate
180 S.requireSuccess("timer_lane = require 'lanes'.configure{with_timers = true}.timer_lane");
181 // make sure we have the timer lane and its cancel method handy
182 S.requireSuccess("assert(timer_lane and timer_lane.cancel)");
183 // as well as the fixture module
184 S.requireSuccess("fixture = require 'fixture'");
185
186 // ---------------------------------------------------------------------------------------------
187
188 SECTION("cancel operation must be a known string")
186 { 189 {
187 // need the timers so that there is a lane running on which we can operate 190 // cancel operation must be a known string
188 std::ignore = S.doString("timer_lane = require 'lanes'.configure{with_timers = true}.timer_lane"); 191 S.requireFailure("timer_lane:cancel('gleh')");
192 S.requireFailure("timer_lane:cancel(function() end)");
193 S.requireFailure("timer_lane:cancel({})");
194 S.requireFailure("timer_lane:cancel(fixture.newuserdata())");
195 S.requireFailure("timer_lane:cancel(fixture.newlightuserdata())");
189 } 196 }
190};
191 197
192// ################################################################################################# 198 // ---------------------------------------------------------------------------------------------
193 199
194TEST_F(LaneCancel, FailsOnBadArguments) 200 SECTION("cancel doesn't expect additional non-number/bool arguments after the mode")
195{ 201 {
196 //FAIL() << "Make sure the failures fail the way we expect them"; 202 S.requireFailure("timer_lane:cancel('soft', 'gleh')");
197 // make sure we have the timer lane and its cancel method handy 203 S.requireFailure("timer_lane:cancel('soft', function() end)");
198 ASSERT_EQ(S.doString("assert(timer_lane and timer_lane.cancel)"), LuaError::OK); 204 S.requireFailure("timer_lane:cancel('soft', {})");
199 // as well as the fixture module 205 S.requireFailure("timer_lane:cancel('soft', fixture.newuserdata())");
200 ASSERT_EQ(S.doString("fixture = require 'fixture'"), LuaError::OK) << S; 206 S.requireFailure("timer_lane:cancel('soft', fixture.newlightuserdata())");
201 207 }
202 // cancel operation must be a known string 208
203 ASSERT_NE(S.doString("timer_lane:cancel('gleh')"), LuaError::OK); 209 // ---------------------------------------------------------------------------------------------
204 ASSERT_NE(S.doString("timer_lane:cancel(function() end)"), LuaError::OK); 210
205 ASSERT_NE(S.doString("timer_lane:cancel({})"), LuaError::OK); 211 SECTION("hook-based cancellation expects a number for the count. IOW, a bool is not valid")
206 ASSERT_NE(S.doString("timer_lane:cancel(fixture.newuserdata())"), LuaError::OK); 212 {
207 ASSERT_NE(S.doString("timer_lane:cancel(fixture.newlightuserdata())"), LuaError::OK); 213 S.requireFailure("timer_lane:cancel('call', true)");
208 214 S.requireFailure("timer_lane:cancel('ret', true)");
209 // cancel doesn't expect additional non-number/bool arguments after the mode 215 S.requireFailure("timer_lane:cancel('line', true)");
210 ASSERT_NE(S.doString("timer_lane:cancel('soft', 'gleh')"), LuaError::OK); 216 S.requireFailure("timer_lane:cancel('count', true)");
211 ASSERT_NE(S.doString("timer_lane:cancel('soft', function() end)"), LuaError::OK); 217 S.requireFailure("timer_lane:cancel('all', true)");
212 ASSERT_NE(S.doString("timer_lane:cancel('soft', {})"), LuaError::OK); 218 }
213 ASSERT_NE(S.doString("timer_lane:cancel('soft', fixture.newuserdata())"), LuaError::OK); 219
214 ASSERT_NE(S.doString("timer_lane:cancel('soft', fixture.newlightuserdata())"), LuaError::OK); 220 // ---------------------------------------------------------------------------------------------
215 221
216 // hook-based cancellation expects a number for the count. IOW, a bool is not valid 222 SECTION("non-hook should only have one number after the mode (the timeout), else it means we have a count")
217 ASSERT_NE(S.doString("timer_lane:cancel('call', true)"), LuaError::OK); 223 {
218 ASSERT_NE(S.doString("timer_lane:cancel('ret', true)"), LuaError::OK); 224 S.requireFailure("timer_lane:cancel('hard', 10, 10)");
219 ASSERT_NE(S.doString("timer_lane:cancel('line', true)"), LuaError::OK); 225 }
220 ASSERT_NE(S.doString("timer_lane:cancel('count', true)"), LuaError::OK); 226
221 ASSERT_NE(S.doString("timer_lane:cancel('all', true)"), LuaError::OK); 227 // ---------------------------------------------------------------------------------------------
222 228
223 // non-hook should only have one number after the mode (the timeout), else it means we have a count 229 SECTION("extra arguments are not accepted either")
224 ASSERT_NE(S.doString("timer_lane:cancel('hard', 10, 10)"), LuaError::OK); 230 {
225 231 S.requireFailure("timer_lane:cancel('hard', 10, true, 10)");
226 // extra arguments are not accepted either 232 S.requireFailure("timer_lane:cancel('call', 10, 10, 10)");
227 ASSERT_NE(S.doString("timer_lane:cancel('hard', 10, true, 10)"), LuaError::OK); 233 S.requireFailure("timer_lane:cancel('line', 10, 10, true, 10)");
228 ASSERT_NE(S.doString("timer_lane:cancel('call', 10, 10, 10)"), LuaError::OK); 234 }
229 ASSERT_NE(S.doString("timer_lane:cancel('line', 10, 10, true, 10)"), LuaError::OK); 235
230 236 // ---------------------------------------------------------------------------------------------
231 // out-of-range hook count is not valid 237
232 ASSERT_NE(S.doString("timer_lane:cancel('call', -1)"), LuaError::OK); 238 SECTION("out-of-range hook count is not valid")
233 ASSERT_NE(S.doString("timer_lane:cancel('call', 0)"), LuaError::OK); 239 {
234 240 S.requireFailure("timer_lane:cancel('call', -1)");
235 // out-of-range duration is not valid 241 S.requireFailure("timer_lane:cancel('call', 0)");
236 ASSERT_NE(S.doString("timer_lane:cancel('soft', -1)"), LuaError::OK); 242 }
243
244 // ---------------------------------------------------------------------------------------------
245
246 SECTION("out-of-range duration is not valid")
247 {
248 S.requireFailure("timer_lane:cancel('soft', -1)");
249 }
237} 250}
238 251
239// ################################################################################################# 252// #################################################################################################
240// ################################################################################################# 253// #################################################################################################
241 254
242INSTANTIATE_TEST_CASE_P( 255TEST_CASE("lane scripted tests")
243 LaneScriptedTests, 256{
244 UnitTestRunner, 257 auto const& _testParam = GENERATE(
245 ::testing::Values( 258 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0
246 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0
247 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertThrows }, 259 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertThrows },
248 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2 260 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2
249 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3 261 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3
250 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4 262 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4
251 FileRunnerParam{ "lane/tasking_communications", TestType::AssertNoLuaError }, 263 FileRunnerParam{ "lane/tasking_communications", TestType::AssertNoLuaError },
252 FileRunnerParam{ "lane/tasking_error", TestType::AssertNoLuaError }, // 6 264 FileRunnerParam{ "lane/tasking_error", TestType::AssertNoLuaError }, // 6
253 FileRunnerParam{ "lane/tasking_join_test", TestType::AssertNoLuaError }, // 7 265 FileRunnerParam{ "lane/tasking_join_test", TestType::AssertNoLuaError }, // 7
254 FileRunnerParam{ "lane/tasking_send_receive_code", TestType::AssertNoLuaError }, 266 FileRunnerParam{ "lane/tasking_send_receive_code", TestType::AssertNoLuaError },
255 FileRunnerParam{ "lane/stdlib_naming", TestType::AssertNoLuaError }, 267 FileRunnerParam{ "lane/stdlib_naming", TestType::AssertNoLuaError },
256 FileRunnerParam{ "coro/basics", TestType::AssertNoLuaError }, // 10 268 FileRunnerParam{ "coro/basics", TestType::AssertNoLuaError }, // 10
257 FileRunnerParam{ "coro/error_handling", TestType::AssertNoLuaError } 269 FileRunnerParam{ "coro/error_handling", TestType::AssertNoLuaError }
258 ) 270 );
259 //,[](::testing::TestParamInfo<FileRunnerParam> const& info_) { return std::string{ info_.param.script };} 271
260); 272 FileRunner _runner(R"(.\lanes\unit_tests\scripts)");
273 _runner.performTest(_testParam);
274}
diff --git a/unit_tests/legacy_tests.cpp b/unit_tests/legacy_tests.cpp
index 2d88190..cb91c93 100644
--- a/unit_tests/legacy_tests.cpp
+++ b/unit_tests/legacy_tests.cpp
@@ -5,75 +5,43 @@
5#if RUN_LEGACY_TESTS 5#if RUN_LEGACY_TESTS
6 6
7// ################################################################################################# 7// #################################################################################################
8// #################################################################################################
8 9
9class LegacyTestRunner : public FileRunner 10TEST_CASE("legacy scripted tests")
10{ 11{
11 public: 12 auto const& _testParam = GENERATE(
12 LegacyTestRunner() 13 FileRunnerParam{ "appendud", TestType::AssertNoLuaError } // 0
13 { 14 , FileRunnerParam{ "atexit", TestType::AssertNoLuaError } // 1
14 [[maybe_unused]] std::filesystem::path const _current{ std::filesystem::current_path() }; 15 , FileRunnerParam{ "atomic", TestType::AssertNoLuaError } // 2
15 std::filesystem::path _path{ R"(.\lanes\tests\)" }; 16 , FileRunnerParam{ "basic", TestType::AssertNoLuaError } // 3
16 root = std::filesystem::canonical(_path).generic_string(); 17 , FileRunnerParam{ "cancel", TestType::AssertNoLuaError } // 4
17 // I need to append that path to the list of locations where modules can be required 18 , FileRunnerParam{ "cyclic", TestType::AssertNoLuaError } // 5
18 // so that the legacy scripts can require"assert" and find assert.lua 19 , FileRunnerParam{ "deadlock", TestType::AssertNoLuaError } // 6
19 std::string _script{"package.path = package.path.."}; 20 , FileRunnerParam{ "errhangtest", TestType::AssertNoLuaError } // 7
20 _script += "';"; 21 , FileRunnerParam{ "error", TestType::AssertNoLuaError } // 8
21 _script += root; 22 , FileRunnerParam{ "fibonacci", TestType::AssertNoLuaError } // 9
22 _script += "/?.lua'"; 23 , FileRunnerParam{ "fifo", TestType::AssertNoLuaError } // 10
23 std::ignore = L.doString(_script.c_str()); 24 , FileRunnerParam{ "finalizer", TestType::AssertNoLuaError } // 11
24 } 25 , FileRunnerParam{ "func_is_string", TestType::AssertNoLuaError } // 12
25}; 26 , FileRunnerParam{ "irayo_closure", TestType::AssertNoLuaError } // 13
27 , FileRunnerParam{ "irayo_recursive", TestType::AssertNoLuaError } // 14
28 , FileRunnerParam{ "keeper", TestType::AssertNoLuaError } // 15
29 //, FileRunnerParam{ "linda_perf", TestType::AssertNoLuaError }
30 , FileRunnerParam{ LUA54_ONLY("manual_register"), TestType::AssertNoLuaError } // 16: uses lfs module, currently not available for non-5.4 flavors
31 , FileRunnerParam{ "nameof", TestType::AssertNoLuaError } // 17
32 , FileRunnerParam{ "objects", TestType::AssertNoLuaError } // 18
33 , FileRunnerParam{ "package", TestType::AssertNoLuaError } // 19
34 , FileRunnerParam{ "pingpong", TestType::AssertNoLuaError } // 20
35 , FileRunnerParam{ "recursive", TestType::AssertNoLuaError } // 21
36 , FileRunnerParam{ "require", TestType::AssertNoLuaError } // 22
37 , FileRunnerParam{ "rupval", TestType::AssertNoLuaError } // 23
38 , FileRunnerParam{ "timer", TestType::AssertNoLuaError } // 24
39 , FileRunnerParam{ LUA54_ONLY("tobeclosed"), TestType::AssertNoLuaError } // 25
40 , FileRunnerParam{ "track_lanes", TestType::AssertNoLuaError } // 26
41 );
26 42
27TEST_P(LegacyTestRunner, LegacyTest) 43 FileRunner _runner(R"(.\lanes\tests\)");
28{ 44 _runner.performTest(_testParam);
29 FileRunnerParam const& _param = GetParam();
30 switch (_param.test) {
31 case TestType::AssertNoLuaError:
32 ASSERT_EQ(L.doFile(root, _param.script), LuaError::OK) << L;
33 break;
34 case TestType::AssertNoThrow:
35 ASSERT_NO_THROW((std::ignore = L.doFile(root, _param.script), L.close())) << L;
36 break;
37 case TestType::AssertThrows:
38 ASSERT_THROW((std::ignore = L.doFile(root, _param.script), L.close()), std::logic_error) << L;
39 break;
40 }
41} 45}
42 46
43INSTANTIATE_TEST_CASE_P(
44 LegacyTests,
45 LegacyTestRunner,
46 ::testing::Values(
47 "appendud" // 0
48 , "atexit" // 1
49 , "atomic" // 2
50 , "basic" // 3
51 , "cancel" // 4
52 , "cyclic" // 5
53 , "deadlock" // 6
54 , "errhangtest" // 7
55 , "error" // 8
56 , "fibonacci" // 9
57 , "fifo" // 10
58 , "finalizer" // 11
59 , "func_is_string" // 12
60 , "irayo_closure" // 13
61 , "irayo_recursive" // 14
62 , "keeper" // 15
63 //, "linda_perf"
64 , LUA54_ONLY("manual_register") // 16: uses lfs module, currently not available for non-5.4 flavors
65 , "nameof" // 17
66 , "objects" // 18
67 , "package" // 19
68 , "pingpong" // 20
69 , "recursive" // 21
70 , "require" // 22
71 , "rupval" // 23
72 , "timer" // 24
73 , LUA54_ONLY("tobeclosed") // 25
74 , "track_lanes" // 26
75 )
76 //, [](::testing::TestParamInfo<FileRunnerParam> const& info_) { return info_.param.script.empty() ? "N/A": std::string{ info_.param.script }; }
77);
78
79#endif // RUN_LEGACY_TESTS \ No newline at end of file 47#endif // RUN_LEGACY_TESTS \ No newline at end of file
diff --git a/unit_tests/linda_tests.cpp b/unit_tests/linda_tests.cpp
index b3bad66..29eb28c 100644
--- a/unit_tests/linda_tests.cpp
+++ b/unit_tests/linda_tests.cpp
@@ -3,340 +3,334 @@
3 3
4// ################################################################################################# 4// #################################################################################################
5 5
6class OneKeeperLindaTests : public ::testing::Test 6TEST_CASE("single Keeper Lindas")
7{ 7{
8 protected:
9 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 8 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
9 S.requireSuccess("lanes = require 'lanes'");
10 10
11 void SetUp() override 11 SECTION("Linda creation")
12 { 12 {
13 std::ignore = S.doString("lanes = require 'lanes'"); 13 // no parameters is ok
14 S.requireSuccess("lanes.linda()");
15 S.requireNotReturnedString("return tostring(lanes.linda())", R"===(Linda: <not a string>)==="); // unspecified name should not result in <not a string>
16
17 // since we have only one keeper, only group 0 is authorized
18 S.requireFailure("lanes.linda(-1)");
19 S.requireSuccess("lanes.linda(0)");
20 S.requireFailure("lanes.linda(1)");
21
22 // any name is ok
23 S.requireSuccess("lanes.linda('')"); // an empty name results in a string conversion of the form "Linda: <some hex value>" that we can't test (but it works)
24 S.requireReturnedString("return tostring(lanes.linda('short name'))", R"===(Linda: short name)===");
25 S.requireReturnedString("return tostring(lanes.linda('very very very very very very long name'))", R"===(Linda: very very very very very very long name)===");
26 S.requireReturnedString("return tostring(lanes.linda('auto'))", R"===(Linda: [string "return tostring(lanes.linda('auto'))"]:1)===");
27
28 if constexpr (LUA_VERSION_NUM == 504) {
29 // a function is acceptable as a __close handler
30 S.requireSuccess("local l <close> = lanes.linda(function() end)");
31 // a callable table too (a callable full userdata as well, but I have none here)
32 S.requireSuccess("local l <close> = lanes.linda(setmetatable({}, {__call = function() end}))");
33 // if the function raises an error, we should get it
34 S.requireFailure("local l <close> = lanes.linda(function() error 'gluh' end)");
35 } else {
36 // no __close support before Lua 5.4
37 S.requireFailure("lanes.linda(function() end)");
38 S.requireFailure("lanes.linda(setmetatable({}, {__call = function() end}))");
39 }
40
41 // mixing parameters in any order is ok: 2 out of 3
42 S.requireSuccess("lanes.linda(0, 'name')");
43 S.requireSuccess("lanes.linda('name', 0)");
44 if constexpr (LUA_VERSION_NUM == 504) {
45 S.requireSuccess("lanes.linda(0, function() end)");
46 S.requireSuccess("lanes.linda(function() end, 0)");
47 S.requireSuccess("lanes.linda('name', function() end)");
48 S.requireSuccess("lanes.linda(function() end, 'name')");
49 }
50
51 // mixing parameters in any order is ok: 3 out of 3
52 if constexpr (LUA_VERSION_NUM == 504) {
53 S.requireSuccess("lanes.linda(0, 'name', function() end)");
54 S.requireSuccess("lanes.linda(0, function() end, 'name')");
55 S.requireSuccess("lanes.linda('name', 0, function() end)");
56 S.requireSuccess("lanes.linda('name', function() end, 0)");
57 S.requireSuccess("lanes.linda(function() end, 0, 'name')");
58 S.requireSuccess("lanes.linda(function() end, 'name', 0)");
59 }
60
61 // unsupported parameters should fail
62 S.requireFailure("lanes.linda(true)");
63 S.requireFailure("lanes.linda(false)");
64 // uncallable table or full userdata
65 S.requireFailure("lanes.linda({})");
66 S.requireFailure("lanes.linda(lanes.linda())");
14 } 67 }
15};
16 68
17TEST_F(OneKeeperLindaTests, LindaCreation) 69 // ---------------------------------------------------------------------------------------------
18{
19 // no parameters is ok
20 EXPECT_EQ(S.doString("lanes.linda()"), LuaError::OK) << S;
21 EXPECT_NE(S.doStringAndRet("return tostring(lanes.linda())"), R"===(Linda: <not a string>)===") << S; // unspecified name should not result in <not a string>
22
23 // since we have only one keeper, only group 0 is authorized
24 EXPECT_NE(S.doString("lanes.linda(-1)"), LuaError::OK);
25 EXPECT_EQ(S.doString("lanes.linda(0)"), LuaError::OK) << S;
26 EXPECT_NE(S.doString("lanes.linda(1)"), LuaError::OK);
27
28 // any name is ok
29 EXPECT_EQ(S.doString("lanes.linda('')"), LuaError::OK) << S; // an empty name results in a string conversion of the form "Linda: <some hex value>" that we can't test (but it works)
30 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('short name'))"), R"===(Linda: short name)===") << S;
31 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('very very very very very very long name'))"), R"===(Linda: very very very very very very long name)===") << S;
32 EXPECT_EQ(S.doStringAndRet("return tostring(lanes.linda('auto'))"), R"===(Linda: [string "return tostring(lanes.linda('auto'))"]:1)===") << S;
33
34 if constexpr (LUA_VERSION_NUM == 504) {
35 // a function is acceptable as a __close handler
36 EXPECT_EQ(S.doString("local l <close> = lanes.linda(function() end)"), LuaError::OK) << S;
37 // a callable table too (a callable full userdata as well, but I have none here)
38 EXPECT_EQ(S.doString("local l <close> = lanes.linda(setmetatable({}, {__call = function() end}))"), LuaError::OK) << S;
39 // if the function raises an error, we should get it
40 EXPECT_NE(S.doString("local l <close> = lanes.linda(function() error 'gluh' end)"), LuaError::OK);
41 } else {
42 // no __close support before Lua 5.4
43 EXPECT_NE(S.doString("lanes.linda(function() end)"), LuaError::OK);
44 EXPECT_NE(S.doString("lanes.linda(setmetatable({}, {__call = function() end}))"), LuaError::OK);
45 }
46 70
47 // mixing parameters in any order is ok: 2 out of 3 71 SECTION("Linda indexing")
48 EXPECT_EQ(S.doString("lanes.linda(0, 'name')"), LuaError::OK) << S; 72 {
49 EXPECT_EQ(S.doString("lanes.linda('name', 0)"), LuaError::OK) << S; 73 // indexing the linda with an unknown string key should fail
50 if constexpr (LUA_VERSION_NUM == 504) { 74 S.requireFailure("return lanes.linda().gouikra");
51 EXPECT_EQ(S.doString("lanes.linda(0, function() end)"), LuaError::OK) << S; 75 // indexing the linda with an unsupported key type should fail
52 EXPECT_EQ(S.doString("lanes.linda(function() end, 0)"), LuaError::OK) << S; 76 S.requireFailure("return lanes.linda()[5]");
53 EXPECT_EQ(S.doString("lanes.linda('name', function() end)"), LuaError::OK) << S; 77 S.requireFailure("return lanes.linda()[false]");
54 EXPECT_EQ(S.doString("lanes.linda(function() end, 'name')"), LuaError::OK) << S; 78 S.requireFailure("return lanes.linda()[{}]");
79 S.requireFailure("return lanes.linda()[function() end]");
55 } 80 }
56 81
57 // mixing parameters in any order is ok: 3 out of 3 82 // ---------------------------------------------------------------------------------------------
58 if constexpr (LUA_VERSION_NUM == 504) { 83 SECTION("linda:send()")
59 EXPECT_EQ(S.doString("lanes.linda(0, 'name', function() end)"), LuaError::OK) << S; 84 {
60 EXPECT_EQ(S.doString("lanes.linda(0, function() end, 'name')"), LuaError::OK) << S; 85 SECTION("timeout")
61 EXPECT_EQ(S.doString("lanes.linda('name', 0, function() end)"), LuaError::OK) << S; 86 {
62 EXPECT_EQ(S.doString("lanes.linda('name', function() end, 0)"), LuaError::OK) << S; 87 // timeout checks
63 EXPECT_EQ(S.doString("lanes.linda(function() end, 0, 'name')"), LuaError::OK) << S; 88 // linda:send() should fail if the timeout is bad
64 EXPECT_EQ(S.doString("lanes.linda(function() end, 'name', 0)"), LuaError::OK) << S; 89 S.requireFailure("lanes.linda():send(-1, 'k', 'v')");
90 // any positive value is ok
91 S.requireSuccess("lanes.linda():send(0, 'k', 'v')");
92 S.requireSuccess("lanes.linda():send(1e20, 'k', 'v')");
93 // nil too (same as 'forever')
94 S.requireSuccess("lanes.linda():send(nil, 'k', 'v')");
95 }
96
97 // -----------------------------------------------------------------------------------------
98
99 SECTION("fails on bad keys")
100 {
101 // key checks
102 // linda:send() should fail if the key is unsupported (nil, table, function, full userdata, reserved light userdata)
103 S.requireFailure("lanes.linda():send(0, nil, 'v')");
104 S.requireFailure("lanes.linda():send(0, {}, 'v')");
105 S.requireFailure("lanes.linda():send(0, function() end, 'v')");
106 S.requireFailure("lanes.linda():send(0, io.stdin, 'v')");
107 S.requireFailure("lanes.linda():send(0, lanes.null, 'v')");
108 S.requireFailure("lanes.linda():send(0, lanes.cancel_error, 'v')");
109 S.requireFailure("local l = lanes.linda(); l:send(0, l.batched, 'v')");
110 }
111
112 // -----------------------------------------------------------------------------------------
113
114 SECTION("succeeds on supported keys")
115 {
116 // supported keys are ok: boolean, number, string, light userdata, deep userdata
117 S.requireSuccess("lanes.linda():send(0, true, 'v')");
118 S.requireSuccess("lanes.linda():send(0, false, 'v')");
119 S.requireSuccess("lanes.linda():send(0, 99, 'v')");
120 S.requireSuccess("local l = lanes.linda(); l:send(0, l:deep(), 'v')");
121 }
122
123 // -----------------------------------------------------------------------------------------
124
125 SECTION("succeeds on deep userdata key")
126 {
127 S.requireSuccess("local l = lanes.linda(); l:send(0, l, 'v')");
128 }
129
130 // -----------------------------------------------------------------------------------------
131
132 SECTION(". fails")
133 {
134 // misuse checks, . instead of :
135 S.requireFailure("lanes.linda().send(nil, 'k', 'v')");
136 }
137
138 // -----------------------------------------------------------------------------------------
139
140 SECTION("unsupported values fail")
141 {
142 // value checks
143 // linda:send() should fail if we don't send anything
144 S.requireFailure("lanes.linda():send()");
145 S.requireFailure("lanes.linda():send(0)");
146 S.requireFailure("lanes.linda():send(0, 'k')");
147 // or non-deep userdata
148 S.requireFailure("lanes.linda():send(0, 'k', fixture.newuserdata())");
149 // or something with a converter that raises an error (maybe that should go to a dedicated __lanesconvert test!)
150 S.requireFailure("lanes.linda():send(0, 'k', setmetatable({}, {__lanesconvert = function(where_) error (where_ .. ': should not send me' end}))");
151 // but a registered non-deep userdata should work
152 S.requireSuccess("lanes.linda():send(0, 'k', io.stdin)");
153 }
65 } 154 }
66 155
67 // unsupported parameters should fail 156 // ---------------------------------------------------------------------------------------------
68 EXPECT_NE(S.doString("lanes.linda(true)"), LuaError::OK);
69 EXPECT_NE(S.doString("lanes.linda(false)"), LuaError::OK);
70 // uncallable table or full userdata
71 EXPECT_NE(S.doString("lanes.linda({})"), LuaError::OK);
72 EXPECT_NE(S.doString("lanes.linda(lanes.linda())"), LuaError::OK);
73}
74
75// #################################################################################################
76
77TEST_F(OneKeeperLindaTests, LindaIndexing)
78{
79 // indexing the linda with an unknown string key should fail
80 EXPECT_NE(S.doString("return lanes.linda().gouikra"), LuaError::OK) << S;
81 // indexing the linda with an unsupported key type should fail
82 EXPECT_NE(S.doString("return lanes.linda()[5]"), LuaError::OK) << S;
83 EXPECT_NE(S.doString("return lanes.linda()[false]"), LuaError::OK) << S;
84 EXPECT_NE(S.doString("return lanes.linda()[{}]"), LuaError::OK) << S;
85 EXPECT_NE(S.doString("return lanes.linda()[function() end]"), LuaError::OK) << S;
86}
87
88// #################################################################################################
89
90TEST_F(OneKeeperLindaTests, LindaSendTimeoutValidation)
91{
92 // timeout checks
93 // linda:send() should fail if the timeout is bad
94 EXPECT_NE(S.doString("lanes.linda():send(-1, 'k', 'v')"), LuaError::OK);
95 // any positive value is ok
96 EXPECT_EQ(S.doString("lanes.linda():send(0, 'k', 'v')"), LuaError::OK) << S;
97 EXPECT_EQ(S.doString("lanes.linda():send(1e20, 'k', 'v')"), LuaError::OK) << S;
98 // nil too (same as 'forever')
99 EXPECT_EQ(S.doString("lanes.linda():send(nil, 'k', 'v')"), LuaError::OK) << S;
100}
101
102// #################################################################################################
103
104TEST_F(OneKeeperLindaTests, LindaSendFailsOnBadKeys)
105{
106 // key checks
107 // linda:send() should fail if the key is unsupported (nil, table, function, full userdata, reserved light userdata)
108 EXPECT_NE(S.doString("lanes.linda():send(0, nil, 'v')"), LuaError::OK);
109 EXPECT_NE(S.doString("lanes.linda():send(0, {}, 'v')"), LuaError::OK);
110 EXPECT_NE(S.doString("lanes.linda():send(0, function() end, 'v')"), LuaError::OK);
111 EXPECT_NE(S.doString("lanes.linda():send(0, io.stdin, 'v')"), LuaError::OK);
112 EXPECT_NE(S.doString("lanes.linda():send(0, lanes.null, 'v')"), LuaError::OK);
113 EXPECT_NE(S.doString("lanes.linda():send(0, lanes.cancel_error, 'v')"), LuaError::OK);
114 EXPECT_NE(S.doString("local l = lanes.linda(); l:send(0, l.batched, 'v')"), LuaError::OK);
115}
116
117// #################################################################################################
118
119TEST_F(OneKeeperLindaTests, LindaSendSucceedsOnSupportedKeys)
120{
121 // supported keys are ok: boolean, number, string, light userdata, deep userdata
122 EXPECT_EQ(S.doString("lanes.linda():send(0, true, 'v')"), LuaError::OK) << S;
123 EXPECT_EQ(S.doString("lanes.linda():send(0, false, 'v')"), LuaError::OK) << S;
124 EXPECT_EQ(S.doString("lanes.linda():send(0, 99, 'v')"), LuaError::OK) << S;
125 EXPECT_EQ(S.doString("local l = lanes.linda(); l:send(0, l:deep(), 'v')"), LuaError::OK) << S;
126}
127
128// #################################################################################################
129
130TEST_F(OneKeeperLindaTests, LindaSendSucceedsOnDeepUserdataKey)
131{
132 EXPECT_EQ(S.doString("local l = lanes.linda(); l:send(0, l, 'v')"), LuaError::OK) << S;
133}
134
135// #################################################################################################
136
137TEST_F(OneKeeperLindaTests, LindaSendSelfValidation)
138{
139 // misuse checks, . instead of :
140 EXPECT_NE(S.doString("lanes.linda().send(nil, 'k', 'v')"), LuaError::OK);
141}
142
143// #################################################################################################
144
145TEST_F(OneKeeperLindaTests, LindaSendValueValidation)
146{
147 // value checks
148 // linda:send() should fail if we don't send anything
149 EXPECT_NE(S.doString("lanes.linda():send()"), LuaError::OK);
150 EXPECT_NE(S.doString("lanes.linda():send(0)"), LuaError::OK);
151 EXPECT_NE(S.doString("lanes.linda():send(0, 'k')"), LuaError::OK);
152 // or non-deep userdata
153 EXPECT_NE(S.doString("lanes.linda():send(0, 'k', fixture.newuserdata())"), LuaError::OK);
154 // or something with a converter that raises an error (maybe that should go to a dedicated __lanesconvert test!)
155 EXPECT_NE(S.doString("lanes.linda():send(0, 'k', setmetatable({}, {__lanesconvert = function(where_) error (where_ .. ': should not send me' end}))"), LuaError::OK);
156 // but a registered non-deep userdata should work
157 EXPECT_EQ(S.doString("lanes.linda():send(0, 'k', io.stdin)"), LuaError::OK);
158}
159
160// #################################################################################################
161
162TEST_F(OneKeeperLindaTests, LindaLimitArgumentValidation)
163{
164 // misuse checks, . instead of :
165 EXPECT_NE(S.doString("lanes.linda().limit()"), LuaError::OK);
166
167 // not enough keys
168 EXPECT_NE(S.doString("lanes.linda():limit()"), LuaError::OK);
169
170 // too many keys?
171 EXPECT_NE(S.doString("lanes.linda():limit('k1', 'k2')"), LuaError::OK);
172 EXPECT_NE(S.doString("lanes.linda():limit('k1', 'k2', 'k3')"), LuaError::OK);
173
174 // non-numeric limit
175 EXPECT_NE(S.doString("lanes.linda():limit('k', false)"), LuaError::OK);
176 EXPECT_NE(S.doString("lanes.linda():limit('k', true)"), LuaError::OK);
177 EXPECT_NE(S.doString("lanes.linda():limit('k', {})"), LuaError::OK);
178 EXPECT_NE(S.doString("lanes.linda():limit('k', lanes.linda():deep())"), LuaError::OK);
179 EXPECT_NE(S.doString("lanes.linda():limit('k', assert)"), LuaError::OK);
180 EXPECT_NE(S.doString("lanes.linda():limit('k', function() end)"), LuaError::OK);
181
182 // negative limit is forbidden
183 EXPECT_NE(S.doString("lanes.linda():limit('k', -1)"), LuaError::OK);
184
185 // we can set a positive limit, or "unlimited"
186 EXPECT_EQ(S.doString("lanes.linda():limit('k', 0)"), LuaError::OK) << S;
187 EXPECT_EQ(S.doString("lanes.linda():limit('k', 1)"), LuaError::OK) << S;
188 EXPECT_EQ(S.doString("lanes.linda():limit('k', 45648946)"), LuaError::OK) << S;
189 EXPECT_EQ(S.doString("lanes.linda():limit('k', 'unlimited')"), LuaError::OK) << S;
190}
191
192// #################################################################################################
193 157
194TEST_F(OneKeeperLindaTests, LindaCollectGarbage) 158 SECTION("linda::collectgarbage()")
195{ 159 {
196 // linda:collectgarbage() doesn't accept extra arguments 160 // linda:collectgarbage() doesn't accept extra arguments
197 EXPECT_NE(S.doString("lanes.linda():collectgarbage(true)"), LuaError::OK) << S; 161 S.requireFailure("lanes.linda():collectgarbage(true)");
198 EXPECT_EQ(S.doString("lanes.linda():collectgarbage()"), LuaError::OK) << S; 162 S.requireSuccess("lanes.linda():collectgarbage()");
199} 163 }
200 164
201// ################################################################################################# 165 // ---------------------------------------------------------------------------------------------
202 166
203TEST_F(OneKeeperLindaTests, LindaCount) 167 SECTION("linda:count()")
204{ 168 {
205 // counting a non-existent key returns nothing 169 // counting a non-existent key returns nothing
206 EXPECT_EQ(S.doString("assert(lanes.linda():count('k') == nil)"), LuaError::OK) << S; 170 S.requireSuccess("assert(lanes.linda():count('k') == nil)");
207 // counting an existing key returns a correct count 171 // counting an existing key returns a correct count
208 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1)"), LuaError::OK) << S; 172 S.requireSuccess("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1)");
209 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a', 'b'); assert(l:count('k') == 2)"), LuaError::OK) << S; 173 S.requireSuccess("local l = lanes.linda(); l:set('k', 'a', 'b'); assert(l:count('k') == 2)");
210} 174 }
211 175
212// ################################################################################################# 176 // ---------------------------------------------------------------------------------------------
213 177
214TEST_F(OneKeeperLindaTests, LindaLimit) 178 SECTION("linda:limit()")
215{ 179 {
216 // we can set an inexistent key to unlimited, it should do nothing 180 SECTION("argument validation")
217 EXPECT_EQ(S.doString("local r,s = lanes.linda():limit('k', 'unlimited'); assert(r==false and s=='under')"), LuaError::OK) << S; 181 {
218 // reading the limit of an unset key should succeed 182 // misuse checks, . instead of :
219 EXPECT_EQ(S.doString("local r,s = lanes.linda():limit('k'); assert(r=='unlimited' and s=='under')"), LuaError::OK) << S; 183 S.requireFailure("lanes.linda().limit()");
220 // reading the limit after we set one should yield the correct value 184
221 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:limit('k', 3); assert(r==false and s=='under'); r,s = l:limit('k'); assert(r==3 and s=='under')"), LuaError::OK) << S; 185 // not enough keys
222 // changing the limit is possible... 186 S.requireFailure("lanes.linda():limit()");
223 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:limit('k', 3); r,s = l:limit('k', 5); r,s = l:limit('k'); assert(r==5 and s=='under', 'b')"), LuaError::OK) << S; 187
224 // ... even if we set a limit below the current count of stored data (which should not change) 188 // too many keys?
225 EXPECT_EQ(S.doString("local l = lanes.linda(); local r,s = l:set('k', 'a', 'b', 'c'); assert(r==false and s=='under'); r,s = l:limit('k', 1); assert(r==false and s=='over' and l:count('k') == 3); r,s = l:limit('k'); assert(r==1 and s=='over')"), LuaError::OK) << S; 189 S.requireFailure("lanes.linda():limit('k1', 'k2')");
226 // we can remove the limit on a key 190 S.requireFailure("lanes.linda():limit('k1', 'k2', 'k3')");
227 EXPECT_EQ(S.doString("lanes.linda():limit('k', 'unlimited')"), LuaError::OK) << S; 191
228 192 // non-numeric limit
229 // emptying a limited key should not remove the limit 193 S.requireFailure("lanes.linda():limit('k', false)");
230 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 5); l:set('k'); assert(l:limit('k')==5)"), LuaError::OK) << S; 194 S.requireFailure("lanes.linda():limit('k', true)");
231} 195 S.requireFailure("lanes.linda():limit('k', {})");
196 S.requireFailure("lanes.linda():limit('k', lanes.linda():deep())");
197 S.requireFailure("lanes.linda():limit('k', assert)");
198 S.requireFailure("lanes.linda():limit('k', function() end)");
199
200 // negative limit is forbidden
201 S.requireFailure("lanes.linda():limit('k', -1)");
202
203 // we can set a positive limit, or "unlimited"
204 S.requireSuccess("lanes.linda():limit('k', 0)");
205 S.requireSuccess("lanes.linda():limit('k', 1)");
206 S.requireSuccess("lanes.linda():limit('k', 45648946)");
207 S.requireSuccess("lanes.linda():limit('k', 'unlimited')");
208 }
209
210 // -----------------------------------------------------------------------------------------
211
212 SECTION("normal operations")
213 {
214 // we can set an inexistent key to unlimited, it should do nothing
215 S.requireSuccess("local r,s = lanes.linda():limit('k', 'unlimited'); assert(r==false and s=='under')");
216 // reading the limit of an unset key should succeed
217 S.requireSuccess("local r,s = lanes.linda():limit('k'); assert(r=='unlimited' and s=='under')");
218 // reading the limit after we set one should yield the correct value
219 S.requireSuccess("local l = lanes.linda(); local r,s = l:limit('k', 3); assert(r==false and s=='under'); r,s = l:limit('k'); assert(r==3 and s=='under')");
220 // changing the limit is possible...
221 S.requireSuccess("local l = lanes.linda(); local r,s = l:limit('k', 3); r,s = l:limit('k', 5); r,s = l:limit('k'); assert(r==5 and s=='under', 'b')");
222 // ... even if we set a limit below the current count of stored data (which should not change)
223 S.requireSuccess("local l = lanes.linda(); local r,s = l:set('k', 'a', 'b', 'c'); assert(r==false and s=='under'); r,s = l:limit('k', 1); assert(r==false and s=='over' and l:count('k') == 3); r,s = l:limit('k'); assert(r==1 and s=='over')");
224 // we can remove the limit on a key
225 S.requireSuccess("lanes.linda():limit('k', 'unlimited')");
226
227 // emptying a limited key should not remove the limit
228 S.requireSuccess("local l = lanes.linda(); l:limit('k', 5); l:set('k'); assert(l:limit('k')==5)");
229 }
230 }
232 231
233// ################################################################################################# 232 // ---------------------------------------------------------------------------------------------
234 233
235TEST_F(OneKeeperLindaTests, LindaRestrict) 234 SECTION("linda::restrict()")
236{ 235 {
237 // we can read the access restriction of an inexistent Linda, it should tell us there is no restriction 236 // we can read the access restriction of an inexistent Linda, it should tell us there is no restriction
238 EXPECT_EQ(S.doString("local r = lanes.linda():restrict('k'); assert(r=='none')"), LuaError::OK) << S; 237 S.requireSuccess("local r = lanes.linda():restrict('k'); assert(r=='none')");
239 // setting an unknown access restriction should fail 238 // setting an unknown access restriction should fail
240 EXPECT_NE(S.doString("lanes.linda():restrict('k', 'gleh')"), LuaError::OK) << S; 239 S.requireFailure("lanes.linda():restrict('k', 'gleh')");
241 // we can set the access restriction of an inexistent Linda, it should store it and return the previous restriction 240 // we can set the access restriction of an inexistent Linda, it should store it and return the previous restriction
242 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'set/get')"), LuaError::OK) << S; 241 S.requireSuccess("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'set/get')");
243 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive')"), LuaError::OK) << S; 242 S.requireSuccess("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive')");
244 243
245 // we can replace the restriction on a restricted linda 244 // we can replace the restriction on a restricted linda
246 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'set/get'); assert(r1=='none' and r2 == 'send/receive')"), LuaError::OK) << S; 245 S.requireSuccess("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'set/get'); assert(r1=='none' and r2 == 'send/receive')");
247 246
248 // we can remove the restriction on a restricted linda 247 // we can remove the restriction on a restricted linda
249 EXPECT_EQ(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'none'); local r3 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive' and r3 == 'none')"), LuaError::OK) << S; 248 S.requireSuccess("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); local r2 = l:restrict('k', 'none'); local r3 = l:restrict('k'); assert(r1=='none' and r2 == 'send/receive' and r3 == 'none')");
250 249
251 // can't use send/receive on a 'set/get'-restricted key 250 // can't use send/receive on a 'set/get'-restricted key
252 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:send('k', 'bob')"), LuaError::OK) << S; 251 S.requireFailure("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:send('k', 'bob')");
253 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:receive('k')"), LuaError::OK) << S; 252 S.requireFailure("local l = lanes.linda(); local r1 = l:restrict('k', 'set/get'); l:receive('k')");
254 // can't use get/set on a 'send/receive'-restricted key 253 // can't use get/set on a 'send/receive'-restricted key
255 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:set('k', 'bob')"), LuaError::OK) << S; 254 S.requireFailure("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:set('k', 'bob')");
256 EXPECT_NE(S.doString("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:get('k')"), LuaError::OK) << S; 255 S.requireFailure("local l = lanes.linda(); local r1 = l:restrict('k', 'send/receive'); l:get('k')");
257 256
258 // emptying a restricted key should not cause the restriction to be forgotten 257 // emptying a restricted key should not cause the restriction to be forgotten
259 EXPECT_EQ(S.doString("local l = lanes.linda(); l:restrict('k', 'set/get'); l:set('k'); assert(l:restrict('k')=='set/get')"), LuaError::OK) << S; 258 S.requireSuccess("local l = lanes.linda(); l:restrict('k', 'set/get'); l:set('k'); assert(l:restrict('k')=='set/get')");
260} 259 }
261 260
262// ################################################################################################# 261 // ---------------------------------------------------------------------------------------------
263 262
264TEST_F(OneKeeperLindaTests, LindaSet) 263 SECTION("linda:set()")
265{ 264 {
266 // we can store more data than the specified limit 265 // we can store more data than the specified limit
267 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a', 'b', 'c'); assert(r == false and s == 'over'); assert(l:count('k') == 3)"), LuaError::OK) << S; 266 S.requireSuccess("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a', 'b', 'c'); assert(r == false and s == 'over'); assert(l:count('k') == 3)");
268 // setting nothing in an inexistent key does not create it 267 // setting nothing in an inexistent key does not create it
269 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k'); assert(l:count('k') == nil)"), LuaError::OK) << S; 268 S.requireSuccess("local l = lanes.linda(); l:set('k'); assert(l:count('k') == nil)");
270 // setting a key with some values yields the correct count 269 // setting a key with some values yields the correct count
271 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1) "), LuaError::OK) << S; 270 S.requireSuccess("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1) ");
272 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a'); assert(r == false and s == 'exact'); assert(l:count('k') == 1)"), LuaError::OK) << S; 271 S.requireSuccess("local l = lanes.linda(); l:limit('k', 1); local r,s = l:set('k', 'a'); assert(r == false and s == 'exact'); assert(l:count('k') == 1)");
273 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a', 'b', 'c', 'd'); assert(l:count('k') == 4) "), LuaError::OK) << S; 272 S.requireSuccess("local l = lanes.linda(); l:set('k', 'a', 'b', 'c', 'd'); assert(l:count('k') == 4) ");
274 // setting nothing in an existing key removes it ... 273 // setting nothing in an existing key removes it ...
275 EXPECT_EQ(S.doString("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1); l:set('k'); assert(l:count('k') == nil) "), LuaError::OK) << S; 274 S.requireSuccess("local l = lanes.linda(); l:set('k', 'a'); assert(l:count('k') == 1); l:set('k'); assert(l:count('k') == nil) ");
276 // ... but not if there is a limit (because we don't want to forget it) 275 // ... but not if there is a limit (because we don't want to forget it)
277 EXPECT_EQ(S.doString("local l = lanes.linda(); l:limit('k', 1); l:set('k', 'a'); l:set('k'); assert(l:count('k') == 0) "), LuaError::OK) << S; 276 S.requireSuccess("local l = lanes.linda(); l:limit('k', 1); l:set('k', 'a'); l:set('k'); assert(l:count('k') == 0) ");
278} 277 }
279 278
280// ################################################################################################# 279 // ---------------------------------------------------------------------------------------------
281 280
282TEST_F(OneKeeperLindaTests, LindaCancel) 281 SECTION("linda:cancel()")
283{ 282 {
284 // unknown linda cancellation mode should raise an error 283 // unknown linda cancellation mode should raise an error
285 EXPECT_NE(S.doString("local l = lanes.linda(); l:cancel('zbougli');"), LuaError::OK) << S; 284 S.requireFailure("local l = lanes.linda(); l:cancel('zbougli');");
286 // cancelling a linda should change its cancel status to 'cancelled' 285 // cancelling a linda should change its cancel status to 'cancelled'
287 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('read'); assert(l.status == 'cancelled')"), LuaError::OK) << S; 286 S.requireSuccess("local l = lanes.linda(); l:cancel('read'); assert(l.status == 'cancelled')");
288 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('write'); assert(l.status == 'cancelled')"), LuaError::OK) << S; 287 S.requireSuccess("local l = lanes.linda(); l:cancel('write'); assert(l.status == 'cancelled')");
289 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('both'); assert(l.status == 'cancelled')"), LuaError::OK) << S; 288 S.requireSuccess("local l = lanes.linda(); l:cancel('both'); assert(l.status == 'cancelled')");
290 // resetting the linda cancel status 289 // resetting the linda cancel status
291 EXPECT_EQ(S.doString("local l = lanes.linda(); l:cancel('none'); assert(l.status == 'active')"), LuaError::OK) << S; 290 S.requireSuccess("local l = lanes.linda(); l:cancel('none'); assert(l.status == 'active')");
292} 291 }
293 292
294// ################################################################################################# 293 // ---------------------------------------------------------------------------------------------
295 294
296TEST_F(OneKeeperLindaTests, LindaWake) 295 SECTION("linda:wake()")
297{ 296 {
298 // unknown linda wake mode should raise an error 297 // unknown linda wake mode should raise an error
299 EXPECT_NE(S.doString("local l = lanes.linda(); l:wake('boulgza');"), LuaError::OK) << S; 298 S.requireFailure("local l = lanes.linda(); l:wake('boulgza');");
300 // waking a linda should not change its cancel status 299 // waking a linda should not change its cancel status
301 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('read'); assert(l.status == 'active')"), LuaError::OK) << S; 300 S.requireSuccess("local l = lanes.linda(); l:wake('read'); assert(l.status == 'active')");
302 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('write'); assert(l.status == 'active')"), LuaError::OK) << S; 301 S.requireSuccess("local l = lanes.linda(); l:wake('write'); assert(l.status == 'active')");
303 EXPECT_EQ(S.doString("local l = lanes.linda(); l:wake('both'); assert(l.status == 'active')"), LuaError::OK) << S; 302 S.requireSuccess("local l = lanes.linda(); l:wake('both'); assert(l.status == 'active')");
303 }
304} 304}
305 305
306// ################################################################################################# 306// #################################################################################################
307// ################################################################################################# 307// #################################################################################################
308 308
309class MultiKeeperLindaTests : public ::testing::Test 309TEST_CASE("multi Keeper Lindas")
310{ 310{
311 protected:
312 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 311 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
313 312
314 void SetUp() override 313 S.requireSuccess("lanes = require 'lanes'.configure{nb_user_keepers = 3}");
315 {
316 std::ignore = S.doString("lanes = require 'lanes'.configure{nb_user_keepers = 3}");
317 }
318};
319 314
320TEST_F(MultiKeeperLindaTests, LindaCreation) 315 S.requireFailure("lanes.linda(-1)");
321{ 316 S.requireSuccess("lanes.linda(0)");
322 EXPECT_NE(S.doString("lanes.linda(-1)"), LuaError::OK); 317 S.requireSuccess("lanes.linda(1)");
323 EXPECT_EQ(S.doString("lanes.linda(0)"), LuaError::OK) << S; 318 S.requireSuccess("lanes.linda(2)");
324 EXPECT_EQ(S.doString("lanes.linda(1)"), LuaError::OK) << S; 319 S.requireSuccess("lanes.linda(3)");
325 EXPECT_EQ(S.doString("lanes.linda(2)"), LuaError::OK) << S; 320 S.requireFailure("lanes.linda(4)");
326 EXPECT_EQ(S.doString("lanes.linda(3)"), LuaError::OK) << S;
327 EXPECT_NE(S.doString("lanes.linda(4)"), LuaError::OK);
328} 321}
329 322
330// ################################################################################################# 323// #################################################################################################
331// ################################################################################################# 324// #################################################################################################
332 325
333INSTANTIATE_TEST_CASE_P( 326TEST_CASE("linda scripted tests")
334 LindaScriptedTests, 327{
335 UnitTestRunner, 328 auto const& _testParam = GENERATE(
336 ::testing::Values(
337 FileRunnerParam{ "linda/send_receive", TestType::AssertNoLuaError }, 329 FileRunnerParam{ "linda/send_receive", TestType::AssertNoLuaError },
338 FileRunnerParam{ "linda/send_registered_userdata", TestType::AssertNoLuaError }, 330 FileRunnerParam{ "linda/send_registered_userdata", TestType::AssertNoLuaError },
339 FileRunnerParam{ "linda/multiple_keepers", TestType::AssertNoLuaError } 331 FileRunnerParam{ "linda/multiple_keepers", TestType::AssertNoLuaError }
340 ) 332 );
341 //,[](::testing::TestParamInfo<FileRunnerParam> const& info_) { return std::string{ info_.param.script }; } 333
342); 334 FileRunner _runner(R"(.\lanes\unit_tests\scripts)");
335 _runner.performTest(_testParam);
336}
diff --git a/unit_tests/shared.cpp b/unit_tests/shared.cpp
index 14b2b13..0825227 100644
--- a/unit_tests/shared.cpp
+++ b/unit_tests/shared.cpp
@@ -98,14 +98,14 @@ namespace
98// ################################################################################################# 98// #################################################################################################
99// ################################################################################################# 99// #################################################################################################
100 100
101TEST(Internals, StackChecker) 101TEST_CASE("stack checker")
102{ 102{
103 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 103 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
104 StackChecker::CallsCassert = false; 104 StackChecker::CallsCassert = false;
105 105
106 auto _doStackCheckerTest = [&_L](lua_CFunction const _f, LuaError const _expected) { 106 auto _doStackCheckerTest = [&_L](lua_CFunction const _f, LuaError const _expected) {
107 lua_pushcfunction(_L, _f); 107 lua_pushcfunction(_L, _f);
108 ASSERT_EQ(ToLuaError(lua_pcall(_L, 0, 0, 0)), _expected); 108 REQUIRE(ToLuaError(lua_pcall(_L, 0, 0, 0)) == _expected);
109 }; 109 };
110 110
111 // function where the StackChecker detects something wrong with the stack 111 // function where the StackChecker detects something wrong with the stack
@@ -289,6 +289,66 @@ LuaError LuaState::loadFile(std::filesystem::path const& root_, std::string_view
289 289
290// ################################################################################################# 290// #################################################################################################
291 291
292void LuaState::requireFailure(std::string_view const& script_)
293{
294 auto const _result{ doString(script_) };
295 REQUIRE(_result != LuaError::OK);
296 if (_result == LuaError::OK) {
297 INFO(luaG_tostring(L, kIdxTop));
298 }
299 lua_settop(L, 0);
300}
301
302// #################################################################################################
303
304void LuaState::requireNotReturnedString(std::string_view const& script_, std::string_view const& unexpected_)
305{
306 auto const _result{ doStringAndRet(script_) };
307 REQUIRE(_result != unexpected_);
308 if (_result == unexpected_) {
309 INFO(_result);
310 }
311 lua_settop(L, 0);
312}
313
314// #################################################################################################
315
316void LuaState::requireReturnedString(std::string_view const& script_, std::string_view const& expected_)
317{
318 auto const _result{ doStringAndRet(script_) };
319 REQUIRE(_result == expected_);
320 if (_result != expected_) {
321 INFO(_result);
322 }
323 lua_settop(L, 0);
324}
325
326// #################################################################################################
327
328void LuaState::requireSuccess(std::string_view const& script_)
329{
330 auto const _result{ doString(script_) };
331 REQUIRE(_result == LuaError::OK);
332 if (_result != LuaError::OK) {
333 INFO(luaG_tostring(L, kIdxTop));
334 }
335 lua_settop(L, 0);
336}
337
338// #################################################################################################
339
340void LuaState::requireSuccess(std::filesystem::path const& root_, std::string_view const& path_)
341{
342 auto const _result{ doFile(root_, path_) };
343 REQUIRE(_result == LuaError::OK);
344 if (_result != LuaError::OK) {
345 INFO(luaG_tostring(L, kIdxTop));
346 }
347 lua_settop(L, 0);
348}
349
350// #################################################################################################
351
292LuaError LuaState::runChunk() const 352LuaError LuaState::runChunk() const
293{ 353{
294 STACK_CHECK_START_ABS(L, 1); // we must start with the chunk on the stack (or an error string if it failed to load) 354 STACK_CHECK_START_ABS(L, 1); // we must start with the chunk on the stack (or an error string if it failed to load)
@@ -300,61 +360,61 @@ LuaError LuaState::runChunk() const
300// ################################################################################################# 360// #################################################################################################
301// ################################################################################################# 361// #################################################################################################
302 362
303TEST(LuaState, DoString) 363TEST_CASE("LuaState::doString")
304{ 364{
305 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 365 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
306 // if the script fails to load, we should find the error message at the top of the stack 366 // if the script fails to load, we should find the error message at the top of the stack
307 ASSERT_TRUE([&L = _L]() { std::ignore = L.doString("function end"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::STRING; }()); 367 REQUIRE([&L = _L]() { std::ignore = L.doString("function end"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::STRING; }());
308 368
309 // if the script runs, the stack should contain its return value 369 // if the script runs, the stack should contain its return value
310 ASSERT_TRUE([&L = _L]() { std::ignore = L.doString("return true"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::BOOLEAN; }()); 370 REQUIRE([&L = _L]() { std::ignore = L.doString("return true"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::BOOLEAN; }());
311 ASSERT_TRUE([&L = _L]() { std::ignore = L.doString("return 'hello'"); return lua_gettop(L) == 1 && luaG_tostring(L, StackIndex{1}) == "hello"; }()); 371 REQUIRE([&L = _L]() { std::ignore = L.doString("return 'hello'"); return lua_gettop(L) == 1 && luaG_tostring(L, StackIndex{1}) == "hello"; }());
312 // or nil if it didn't return anything 372 // or nil if it didn't return anything
313 ASSERT_TRUE([&L = _L]() { std::ignore = L.doString("return"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::NIL; }()); 373 REQUIRE([&L = _L]() { std::ignore = L.doString("return"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::NIL; }());
314 374
315 // on failure, doStringAndRet returns "", and the error message is on the stack 375 // on failure, doStringAndRet returns "", and the error message is on the stack
316 ASSERT_TRUE([&L = _L]() { return L.doStringAndRet("function end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::STRING && luaG_tostring(L, StackIndex{1}) != ""; }()); 376 REQUIRE([&L = _L]() { return L.doStringAndRet("function end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::STRING && luaG_tostring(L, StackIndex{ 1 }) != ""; }());
317 // on success doStringAndRet returns the string returned by the script, that is also at the top of the stack 377 // on success doStringAndRet returns the string returned by the script, that is also at the top of the stack
318 ASSERT_TRUE([&L = _L]() { return L.doStringAndRet("return 'hello'") == "hello" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::STRING && luaG_tostring(L, StackIndex{1}) == "hello"; }()); 378 REQUIRE([&L = _L]() { return L.doStringAndRet("return 'hello'") == "hello" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::STRING && luaG_tostring(L, StackIndex{ 1 }) == "hello"; }());
319 // if the returned value is not (convertible to) a string, we should get an empty string out of doStringAndRet 379 // if the returned value is not (convertible to) a string, we should get an empty string out of doStringAndRet
320 ASSERT_TRUE([&L = _L]() { return L.doStringAndRet("return function() end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::FUNCTION && luaG_tostring(L, StackIndex{1}) == ""; }()); 380 REQUIRE([&L = _L]() { return L.doStringAndRet("return function() end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::FUNCTION && luaG_tostring(L, StackIndex{ 1 }) == ""; }());
321} 381}
322 382
323// ################################################################################################# 383// #################################################################################################
324// ################################################################################################# 384// #################################################################################################
325// UnitTestRunner 385// FileRunner
326// ################################################################################################# 386// #################################################################################################
327// ################################################################################################# 387// #################################################################################################
328 388
329UnitTestRunner::UnitTestRunner() 389FileRunner::FileRunner(std::string_view const& where_)
390: LuaState{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }
330{ 391{
331 [[maybe_unused]] std::filesystem::path const _current{ std::filesystem::current_path() }; 392 [[maybe_unused]] std::filesystem::path const _current{ std::filesystem::current_path() };
332 std::filesystem::path _assertPath{ R"(.\lanes\unit_tests\scripts)" }; 393 std::filesystem::path _path{ where_ };
394 root = std::filesystem::canonical(_path).generic_string();
333 // I need to append that path to the list of locations where modules can be required 395 // I need to append that path to the list of locations where modules can be required
334 // so that the scripts can require "_assert" and find _assert.lua (same with "_utils.lua") 396 // so that the legacy scripts can require"assert" and find assert.lua
335 std::string _script{ "package.path = package.path.." }; 397 std::string _script{ "package.path = package.path.." };
336 _script += "';"; 398 _script += "';";
337 _script += std::filesystem::canonical(_assertPath).generic_string(); 399 _script += root;
338 _script += "/?.lua'"; 400 _script += "/?.lua'";
339 std::ignore = L.doString(_script.c_str()); 401 std::ignore = doString(_script.c_str());
340
341 root = std::filesystem::canonical(R"(.\lanes\unit_tests\scripts)").generic_string();
342} 402}
343 403
344// ################################################################################################# 404// #################################################################################################
345 405
346TEST_P(UnitTestRunner, ScriptedTest) 406void FileRunner::performTest(FileRunnerParam const& testParam_)
347{ 407{
348 FileRunnerParam const& _param = GetParam(); 408 INFO(testParam_.script);
349 switch (_param.test) { 409 switch (testParam_.test) {
350 case TestType::AssertNoLuaError: 410 case TestType::AssertNoLuaError:
351 ASSERT_EQ(L.doFile(root, _param.script), LuaError::OK) << L; 411 requireSuccess(root, testParam_.script);
352 break; 412 break;
353 case TestType::AssertNoThrow: 413 case TestType::AssertNoThrow:
354 ASSERT_NO_THROW((std::ignore = L.doFile(root, _param.script), L.close())) << L; 414 REQUIRE_NOTHROW((std::ignore = doFile(root, testParam_.script), close()));
355 break; 415 break;
356 case TestType::AssertThrows: 416 case TestType::AssertThrows:
357 ASSERT_THROW((std::ignore = L.doFile(root, _param.script), L.close()), std::logic_error) << L; 417 REQUIRE_THROWS_AS((std::ignore = doFile(root, testParam_.script), close()), std::logic_error);
358 break; 418 break;
359 } 419 }
360} 420}
diff --git a/unit_tests/shared.h b/unit_tests/shared.h
index bf3a747..2a32269 100644
--- a/unit_tests/shared.h
+++ b/unit_tests/shared.h
@@ -20,6 +20,8 @@ class LuaState
20 20
21 LuaState(LuaState&& rhs_) = default; 21 LuaState(LuaState&& rhs_) = default;
22 22
23 public:
24
23 operator lua_State*() const { return L; } 25 operator lua_State*() const { return L; }
24 26
25 void stackCheck(int delta_) { STACK_CHECK(L, delta_); } 27 void stackCheck(int delta_) { STACK_CHECK(L, delta_); }
@@ -35,6 +37,11 @@ class LuaState
35 LuaError loadString(std::string_view const& str_) const; 37 LuaError loadString(std::string_view const& str_) const;
36 [[nodiscard]] 38 [[nodiscard]]
37 LuaError loadFile(std::filesystem::path const& root_, std::string_view const& str_) const; 39 LuaError loadFile(std::filesystem::path const& root_, std::string_view const& str_) const;
40 void requireFailure(std::string_view const& script_);
41 void requireNotReturnedString(std::string_view const& script_, std::string_view const& unexpected_);
42 void requireReturnedString(std::string_view const& script_, std::string_view const& expected_);
43 void requireSuccess(std::string_view const& script_);
44 void requireSuccess(std::filesystem::path const& root_, std::string_view const& path_);
38 [[nodiscard]] 45 [[nodiscard]]
39 LuaError runChunk() const; 46 LuaError runChunk() const;
40 47
@@ -45,9 +52,6 @@ class LuaState
45 } 52 }
46}; 53};
47 54
48#define LUA_EXPECT_SUCCESS(S_, WHAT_) { LuaState S{ std::move(S_) }; EXPECT_EQ(S.WHAT_, LuaError::OK) << S; }
49#define LUA_EXPECT_FAILURE(S_, WHAT_) { LuaState S{ std::move(S_) }; EXPECT_NE(S.WHAT_, LuaError::OK) << S; }
50
51// ################################################################################################# 55// #################################################################################################
52 56
53enum class TestType 57enum class TestType
@@ -63,33 +67,17 @@ struct FileRunnerParam
63 TestType test; 67 TestType test;
64}; 68};
65 69
66class FileRunner : public ::testing::TestWithParam<FileRunnerParam> 70class FileRunner : private LuaState
67{ 71{
68 protected: 72 private:
69 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
70 std::string root;
71 73
72 ~FileRunner() override 74 std::string root;
73 {
74 lua_settop(L, 0);
75 }
76 void SetUp() override
77 {
78 lua_settop(L, 0);
79 }
80 75
81 void TearDown() override 76 public:
82 {
83 lua_settop(L, 0);
84 }
85};
86 77
87// ################################################################################################# 78 FileRunner(std::string_view const& where_);
88 79
89class UnitTestRunner : public FileRunner 80 void performTest(FileRunnerParam const& testParam_);
90{
91 public:
92 UnitTestRunner();
93}; 81};
94 82
95// ################################################################################################# 83// #################################################################################################