| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 | 
							- /*
 
-  *  Created by Martin on 31/08/2017.
 
-  *
 
-  *  Distributed under the Boost Software License, Version 1.0. (See accompanying
 
-  *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
 
-  */
 
- #include "catch_session.h"
 
- #include "catch_commandline.h"
 
- #include "catch_console_colour.h"
 
- #include "catch_enforce.h"
 
- #include "catch_list.h"
 
- #include "catch_context.h"
 
- #include "catch_run_context.h"
 
- #include "catch_stream.h"
 
- #include "catch_test_spec.h"
 
- #include "catch_version.h"
 
- #include "catch_interfaces_reporter.h"
 
- #include "catch_random_number_generator.h"
 
- #include "catch_startup_exception_registry.h"
 
- #include "catch_text.h"
 
- #include "catch_stream.h"
 
- #include "catch_windows_h_proxy.h"
 
- #include "../reporters/catch_reporter_listening.h"
 
- #include <cstdlib>
 
- #include <iomanip>
 
- #include <set>
 
- #include <iterator>
 
- namespace Catch {
 
-     namespace {
 
-         const int MaxExitCode = 255;
 
-         IStreamingReporterPtr createReporter(std::string const& reporterName, IConfigPtr const& config) {
 
-             auto reporter = Catch::getRegistryHub().getReporterRegistry().create(reporterName, config);
 
-             CATCH_ENFORCE(reporter, "No reporter registered with name: '" << reporterName << "'");
 
-             return reporter;
 
-         }
 
-         IStreamingReporterPtr makeReporter(std::shared_ptr<Config> const& config) {
 
-             if (Catch::getRegistryHub().getReporterRegistry().getListeners().empty()) {
 
-                 return createReporter(config->getReporterName(), config);
 
-             }
 
-             // On older platforms, returning std::unique_ptr<ListeningReporter>
 
-             // when the return type is std::unique_ptr<IStreamingReporter>
 
-             // doesn't compile without a std::move call. However, this causes
 
-             // a warning on newer platforms. Thus, we have to work around
 
-             // it a bit and downcast the pointer manually.
 
-             auto ret = std::unique_ptr<IStreamingReporter>(new ListeningReporter);
 
-             auto& multi = static_cast<ListeningReporter&>(*ret);
 
-             auto const& listeners = Catch::getRegistryHub().getReporterRegistry().getListeners();
 
-             for (auto const& listener : listeners) {
 
-                 multi.addListener(listener->create(Catch::ReporterConfig(config)));
 
-             }
 
-             multi.addReporter(createReporter(config->getReporterName(), config));
 
-             return ret;
 
-         }
 
-         class TestGroup {
 
-         public:
 
-             explicit TestGroup(std::shared_ptr<Config> const& config)
 
-             : m_config{config}
 
-             , m_context{config, makeReporter(config)}
 
-             {
 
-                 auto const& allTestCases = getAllTestCasesSorted(*m_config);
 
-                 m_matches = m_config->testSpec().matchesByFilter(allTestCases, *m_config);
 
-                 auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
 
-                 if (m_matches.empty() && invalidArgs.empty()) {
 
-                     for (auto const& test : allTestCases)
 
-                         if (!test.isHidden())
 
-                             m_tests.emplace(&test);
 
-                 } else {
 
-                     for (auto const& match : m_matches)
 
-                         m_tests.insert(match.tests.begin(), match.tests.end());
 
-                 }
 
-             }
 
-             Totals execute() {
 
-                 auto const& invalidArgs = m_config->testSpec().getInvalidArgs();
 
-                 Totals totals;
 
-                 m_context.testGroupStarting(m_config->name(), 1, 1);
 
-                 for (auto const& testCase : m_tests) {
 
-                     if (!m_context.aborting())
 
-                         totals += m_context.runTest(*testCase);
 
-                     else
 
-                         m_context.reporter().skipTest(*testCase);
 
-                 }
 
-                 for (auto const& match : m_matches) {
 
-                     if (match.tests.empty()) {
 
-                         m_context.reporter().noMatchingTestCases(match.name);
 
-                         totals.error = -1;
 
-                     }
 
-                 }
 
-                 if (!invalidArgs.empty()) {
 
-                     for (auto const& invalidArg: invalidArgs)
 
-                          m_context.reporter().reportInvalidArguments(invalidArg);
 
-                 }
 
-                 m_context.testGroupEnded(m_config->name(), totals, 1, 1);
 
-                 return totals;
 
-             }
 
-         private:
 
-             using Tests = std::set<TestCase const*>;
 
-             std::shared_ptr<Config> m_config;
 
-             RunContext m_context;
 
-             Tests m_tests;
 
-             TestSpec::Matches m_matches;
 
-         };
 
-         void applyFilenamesAsTags(Catch::IConfig const& config) {
 
-             auto& tests = const_cast<std::vector<TestCase>&>(getAllTestCasesSorted(config));
 
-             for (auto& testCase : tests) {
 
-                 auto tags = testCase.tags;
 
-                 std::string filename = testCase.lineInfo.file;
 
-                 auto lastSlash = filename.find_last_of("\\/");
 
-                 if (lastSlash != std::string::npos) {
 
-                     filename.erase(0, lastSlash);
 
-                     filename[0] = '#';
 
-                 }
 
-                 auto lastDot = filename.find_last_of('.');
 
-                 if (lastDot != std::string::npos) {
 
-                     filename.erase(lastDot);
 
-                 }
 
-                 tags.push_back(std::move(filename));
 
-                 setTags(testCase, tags);
 
-             }
 
-         }
 
-     } // anon namespace
 
-     Session::Session() {
 
-         static bool alreadyInstantiated = false;
 
-         if( alreadyInstantiated ) {
 
-             CATCH_TRY { CATCH_INTERNAL_ERROR( "Only one instance of Catch::Session can ever be used" ); }
 
-             CATCH_CATCH_ALL { getMutableRegistryHub().registerStartupException(); }
 
-         }
 
-         // There cannot be exceptions at startup in no-exception mode.
 
- #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
 
-         const auto& exceptions = getRegistryHub().getStartupExceptionRegistry().getExceptions();
 
-         if ( !exceptions.empty() ) {
 
-             config();
 
-             getCurrentMutableContext().setConfig(m_config);
 
-             m_startupExceptions = true;
 
-             Colour colourGuard( Colour::Red );
 
-             Catch::cerr() << "Errors occurred during startup!" << '\n';
 
-             // iterate over all exceptions and notify user
 
-             for ( const auto& ex_ptr : exceptions ) {
 
-                 try {
 
-                     std::rethrow_exception(ex_ptr);
 
-                 } catch ( std::exception const& ex ) {
 
-                     Catch::cerr() << Column( ex.what() ).indent(2) << '\n';
 
-                 }
 
-             }
 
-         }
 
- #endif
 
-         alreadyInstantiated = true;
 
-         m_cli = makeCommandLineParser( m_configData );
 
-     }
 
-     Session::~Session() {
 
-         Catch::cleanUp();
 
-     }
 
-     void Session::showHelp() const {
 
-         Catch::cout()
 
-                 << "\nCatch v" << libraryVersion() << "\n"
 
-                 << m_cli << std::endl
 
-                 << "For more detailed usage please see the project docs\n" << std::endl;
 
-     }
 
-     void Session::libIdentify() {
 
-         Catch::cout()
 
-                 << std::left << std::setw(16) << "description: " << "A Catch2 test executable\n"
 
-                 << std::left << std::setw(16) << "category: " << "testframework\n"
 
-                 << std::left << std::setw(16) << "framework: " << "Catch Test\n"
 
-                 << std::left << std::setw(16) << "version: " << libraryVersion() << std::endl;
 
-     }
 
-     int Session::applyCommandLine( int argc, char const * const * argv ) {
 
-         if( m_startupExceptions )
 
-             return 1;
 
-         auto result = m_cli.parse( clara::Args( argc, argv ) );
 
-         if( !result ) {
 
-             config();
 
-             getCurrentMutableContext().setConfig(m_config);
 
-             Catch::cerr()
 
-                 << Colour( Colour::Red )
 
-                 << "\nError(s) in input:\n"
 
-                 << Column( result.errorMessage() ).indent( 2 )
 
-                 << "\n\n";
 
-             Catch::cerr() << "Run with -? for usage\n" << std::endl;
 
-             return MaxExitCode;
 
-         }
 
-         if( m_configData.showHelp )
 
-             showHelp();
 
-         if( m_configData.libIdentify )
 
-             libIdentify();
 
-         m_config.reset();
 
-         return 0;
 
-     }
 
- #if defined(CATCH_CONFIG_WCHAR) && defined(_WIN32) && defined(UNICODE)
 
-     int Session::applyCommandLine( int argc, wchar_t const * const * argv ) {
 
-         char **utf8Argv = new char *[ argc ];
 
-         for ( int i = 0; i < argc; ++i ) {
 
-             int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr );
 
-             utf8Argv[ i ] = new char[ bufSize ];
 
-             WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr );
 
-         }
 
-         int returnCode = applyCommandLine( argc, utf8Argv );
 
-         for ( int i = 0; i < argc; ++i )
 
-             delete [] utf8Argv[ i ];
 
-         delete [] utf8Argv;
 
-         return returnCode;
 
-     }
 
- #endif
 
-     void Session::useConfigData( ConfigData const& configData ) {
 
-         m_configData = configData;
 
-         m_config.reset();
 
-     }
 
-     int Session::run() {
 
-         if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeStart ) != 0 ) {
 
-             Catch::cout() << "...waiting for enter/ return before starting" << std::endl;
 
-             static_cast<void>(std::getchar());
 
-         }
 
-         int exitCode = runInternal();
 
-         if( ( m_configData.waitForKeypress & WaitForKeypress::BeforeExit ) != 0 ) {
 
-             Catch::cout() << "...waiting for enter/ return before exiting, with code: " << exitCode << std::endl;
 
-             static_cast<void>(std::getchar());
 
-         }
 
-         return exitCode;
 
-     }
 
-     clara::Parser const& Session::cli() const {
 
-         return m_cli;
 
-     }
 
-     void Session::cli( clara::Parser const& newParser ) {
 
-         m_cli = newParser;
 
-     }
 
-     ConfigData& Session::configData() {
 
-         return m_configData;
 
-     }
 
-     Config& Session::config() {
 
-         if( !m_config )
 
-             m_config = std::make_shared<Config>( m_configData );
 
-         return *m_config;
 
-     }
 
-     int Session::runInternal() {
 
-         if( m_startupExceptions )
 
-             return 1;
 
-         if (m_configData.showHelp || m_configData.libIdentify) {
 
-             return 0;
 
-         }
 
-         CATCH_TRY {
 
-             config(); // Force config to be constructed
 
-             seedRng( *m_config );
 
-             if( m_configData.filenamesAsTags )
 
-                 applyFilenamesAsTags( *m_config );
 
-             // Handle list request
 
-             if( Option<std::size_t> listed = list( m_config ) )
 
-                 return static_cast<int>( *listed );
 
-             TestGroup tests { m_config };
 
-             auto const totals = tests.execute();
 
-             if( m_config->warnAboutNoTests() && totals.error == -1 )
 
-                 return 2;
 
-             // Note that on unices only the lower 8 bits are usually used, clamping
 
-             // the return value to 255 prevents false negative when some multiple
 
-             // of 256 tests has failed
 
-             return (std::min) (MaxExitCode, (std::max) (totals.error, static_cast<int>(totals.assertions.failed)));
 
-         }
 
- #if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS)
 
-         catch( std::exception& ex ) {
 
-             Catch::cerr() << ex.what() << std::endl;
 
-             return MaxExitCode;
 
-         }
 
- #endif
 
-     }
 
- } // end namespace Catch
 
 
  |