Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
catch_session.cpp
Go to the documentation of this file.
1/*
2 * Created by Martin on 31/08/2017.
3 *
4 * Distributed under the Boost Software License, Version 1.0. (See accompanying
5 * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 */
7
8#include "catch_session.h"
9#include "catch_commandline.h"
11#include "catch_enforce.h"
12#include "catch_list.h"
13#include "catch_context.h"
14#include "catch_run_context.h"
15#include "catch_stream.h"
16#include "catch_test_spec.h"
17#include "catch_version.h"
21#include "catch_text.h"
22#include "catch_stream.h"
25
26#include <cstdlib>
27#include <iomanip>
28
29namespace Catch {
30
31 namespace {
32 const int MaxExitCode = 255;
33
34 IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
35 auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
36 CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
37
38 return reporter;
39 }
40
41 IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
42 if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
43 return createReporter(config->getReporterName(), config);
44 }
45
46 // On older platforms, returning std::unique_ptr<ListeningReporter>
47 // when the return type is std::unique_ptr<IStreamingReporter>
48 // doesn't compile without a std::move call. However, this causes
49 // a warning on newer platforms. Thus, we have to work around
50 // it a bit and downcast the pointer manually.
51 auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
52 auto& multi = static_cast<ListeningReporter&>(*ret);
53 auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
54 for (auto const& listener : listeners) {
55 multi.addListener(listener->create(Catch::ReporterConfig(config)));
56 }
57 multi.addReporter(createReporter(config->getReporterName(), config));
58 return ret;
59 }
60
61
62 Catch::Totals runTests(std::shared_ptr<Config> const& config) {
63 auto reporter = makeReporter(config);
64
65 RunContext context(config, std::move(reporter));
66
67 Totals totals;
68
69 context.testGroupStarting(config->name(), 1, 1);
70
71 TestSpec testSpec = config->testSpec();
72
73 auto const& allTestCases = getAllTestCasesSorted(*config);
74 for (auto const& testCase : allTestCases) {
75 bool matching = (!testSpec.hasFilters() && !testCase.isHidden()) ||
76 (testSpec.hasFilters() && matchTest(testCase, testSpec, *config));
77
78 if (!context.aborting() && matching)
79 totals += context.runTest(testCase);
80 else
81 context.reporter().skipTest(testCase);
82 }
83
84 if (config->warnAboutNoTests() && totals.testCases.total() == 0) {
85 ReusableStringStream testConfig;
86
87 bool first = true;
88 for (const auto& input : config->getTestsOrTags()) {
89 if (!first) { testConfig << ' '; }
90 first = false;
91 testConfig << input;
92 }
93
94 context.reporter().noMatchingTestCases(testConfig.str());
95 totals.error = -1;
96 }
97
98 context.testGroupEnded(config->name(), totals, 1, 1);
99 return totals;
100 }
101
102 void applyFilenamesAsTags(Catch::IConfig const& config) {
103 auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
104 for (auto& testCase : tests) {
105 auto tags = testCase.tags;
106
107 std::string filename = testCase.lineInfo.file;
108 auto lastSlash = filename.find_last_of("\\/");
109 if (lastSlash != std::string::npos) {
110 filename.erase(0, lastSlash);
111 filename[0] = '#';
112 }
113
114 auto lastDot = filename.find_last_of('.');
115 if (lastDot != std::string::npos) {
116 filename.erase(lastDot);
117 }
118
119 tags.push_back(std::move(filename));
120 setTags(testCase, tags);
121 }
122 }
123
124 } // anon namespace
125
127 static bool alreadyInstantiated = false;
128 if( alreadyInstantiated ) {
129 CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
131 }
132
133 // There cannot be exceptions at startup in no-exception mode.
134#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
135 const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
136 if ( !exceptions.empty() ) {
137 m_startupExceptions = true;
138 Colour colourGuard( Colour::Red );
139 Catch::cerr() << "Errors occurred during startup!" << '\n';
140 // iterate over all exceptions and notify user
141 for ( const auto& ex_ptr : exceptions ) {
142 try {
143 std::rethrow_exception(ex_ptr);
144 } catch ( std::exception const& ex ) {
145 Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
146 }
147 }
148 }
149#endif
150
151 alreadyInstantiated = true;
152 m_cli = makeCommandLineParser( m_configData );
153 }
157
158 void Session::showHelp() const {
160 << "\nCatch v" << libraryVersion() << "\n"
161 << m_cli << std::endl
162 << "For more detailed usage please see the project docs\n" << std::endl;
163 }
166 << std::left << std::setw(16) << "description: " << "A Catch test executable\n"
167 << std::left << std::setw(16) << "category: " << "testframework\n"
168 << std::left << std::setw(16) << "framework: " << "Catch Test\n"
169 << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
170 }
171
172 int Session::applyCommandLine( int argc, char const * const * argv ) {
173 if( m_startupExceptions )
174 return 1;
175
176 auto result = m_cli.parse( clara::Args( argc, argv ) );
177 if( !result ) {
178 config();
181 << Colour( Colour::Red )
182 << "\nError(s) in input:\n"
183 << Column( result.errorMessage() ).indent( 2 )
184 << "\n\n";
185 Catch::cerr() << "Run with -? for usage\n" << std::endl;
186 return MaxExitCode;
187 }
188
189 if( m_configData.showHelp )
190 showHelp();
191 if( m_configData.libIdentify )
192 libIdentify();
193 m_config.reset();
194 return 0;
195 }
196
197#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(UNICODE)
198 int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
199
200 char **utf8Argv = new char *[ argc ];
201
202 for ( int i = 0; i < argc; ++i ) {
203 int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL );
204
205 utf8Argv[ i ] = new char[ bufSize ];
206
207 WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL );
208 }
209
210 int returnCode = applyCommandLine( argc, utf8Argv );
211
212 for ( int i = 0; i < argc; ++i )
213 delete [] utf8Argv[ i ];
214
215 delete [] utf8Argv;
216
217 return returnCode;
218 }
219#endif
220
221 void Session::useConfigData( ConfigData const& configData ) {
222 m_configData = configData;
223 m_config.reset();
224 }
225
227 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
228 Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
229 static_cast<void>(std::getchar());
230 }
231 int exitCode = runInternal();
232 if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
233 Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
234 static_cast<void>(std::getchar());
235 }
236 return exitCode;
237 }
238
240 return m_cli;
241 }
242 void Session::cli( clara::Parser const& newParser ) {
243 m_cli = newParser;
244 }
246 return m_configData;
247 }
249 if( !m_config )
250 m_config = std::make_shared<Config>( m_configData );
251 return *m_config;
252 }
253
254 int Session::runInternal() {
255 if( m_startupExceptions )
256 return 1;
257
258 if (m_configData.showHelp || m_configData.libIdentify) {
259 return 0;
260 }
261
262 CATCH_TRY {
263 config(); // Force config to be constructed
264
265 seedRng( *m_config );
266
267 if( m_configData.filenamesAsTags )
268 applyFilenamesAsTags( *m_config );
269
270 // Handle list request
271 if( Option<std::size_t> listed = list( m_config ) )
272 return static_cast<int>( *listed );
273
274 auto totals = runTests( m_config );
275 // Note that on unices only the lower 8 bits are usually used, clamping
276 // the return value to 255 prevents false negative when some multiple
277 // of 256 tests has failed
278 return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
279 }
280#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
281 catch( std::exception& ex ) {
282 Catch::cerr() << ex.what() << std::endl;
283 return MaxExitCode;
284 }
285#endif
286 }
287
288} // end namespace Catch
#define CATCH_TRY
#define CATCH_CATCH_ALL
#define CATCH_INTERNAL_ERROR(msg)
#define CATCH_ENFORCE(condition, msg)
clara::Parser const & cli() const
void useConfigData(ConfigData const &configData)
void showHelp() const
~Session() override
ConfigData & configData()
int applyCommandLine(int argc, char const *const *argv)
std::vector< std::exception_ptr > const & getExceptions() const noexcept
auto indent(size_t newIndent) -> Column &
Definition clara.hpp:209
char ** argv
std::ostream & cout()
void seedRng(IConfig const &config)
void setTags(TestCaseInfo &testCaseInfo, std::vector< std::string > tags)
std::unique_ptr< IStreamingReporter > IStreamingReporterPtr
Version const & libraryVersion()
std::ostream & cerr()
IMutableRegistryHub & getMutableRegistryHub()
IRegistryHub const & getRegistryHub()
IMutableContext & getCurrentMutableContext()
Option< std::size_t > list(std::shared_ptr< Config > const &config)
std::shared_ptr< IConfig const > IConfigPtr
std::vector< TestCase > const & getAllTestCasesSorted(IConfig const &config)
bool matchTest(TestCase const &testCase, TestSpec const &testSpec, IConfig const &config)
clara::Parser makeCommandLineParser(ConfigData &config)
sysio::client::http::http_context context
Definition main.cpp:200
void multi(const bn::CurveParam &cp)
Definition sample.cpp:224
WaitForKeypress::When waitForKeypress
virtual void setConfig(IConfigPtr const &config)=0
virtual void registerStartupException() noexcept=0
virtual StartupExceptionRegistry const & getStartupExceptionRegistry() const =0
virtual IReporterRegistry const & getReporterRegistry() const =0
virtual Listeners const & getListeners() const =0
virtual IStreamingReporterPtr create(std::string const &name, IConfigPtr const &config) const =0
auto parse(std::string const &exeName, TokenStream const &tokens) const -> InternalParseResult override
Definition clara.hpp:1185
CK_RV ret