diff --git a/src/catch2/internal/catch_commandline.cpp b/src/catch2/internal/catch_commandline.cpp index 4ce085ca..ca0e1c20 100644 --- a/src/catch2/internal/catch_commandline.cpp +++ b/src/catch2/internal/catch_commandline.cpp @@ -135,6 +135,10 @@ namespace Catch { return ParserResult::ok( ParseResultType::Matched ); }; auto const setReporter = [&]( std::string const& reporterSpec ) { + if ( reporterSpec.empty() ) { + return ParserResult::runtimeError( "Received empty reporter spec." ); + } + IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories(); // clear the default reporter @@ -143,21 +147,33 @@ namespace Catch { config._nonDefaultReporterSpecifications = true; } + // Exactly one of the reporters may be specified without an output // file, in which case it defaults to the output specified by "-o" // (or standard output). static constexpr auto separator = "::"; static constexpr size_t separatorSize = 2; - auto separatorPos = reporterSpec.find( separator ); - const bool containsFileName = separatorPos != reporterSpec.npos; + auto fileNameSeparatorPos = reporterSpec.find( separator ); + const bool containsFileName = fileNameSeparatorPos != reporterSpec.npos; + if ( containsFileName ) { + auto nextSeparatorPos = reporterSpec.find( + separator, fileNameSeparatorPos + separatorSize ); + if ( nextSeparatorPos != reporterSpec.npos ) { + return ParserResult::runtimeError( + "Too many separators in reporter spec '" + reporterSpec + '\'' ); + } + } + std::string reporterName; Optional outputFileName; - if (!containsFileName) { - reporterName = reporterSpec; - } else { - reporterName = reporterSpec.substr( 0, separatorPos ); + reporterName = reporterSpec.substr( 0, fileNameSeparatorPos ); + if ( reporterName.empty() ) { + return ParserResult::runtimeError( "Reporter name cannot be empty." ); + } + + if ( containsFileName ) { outputFileName = reporterSpec.substr( - separatorPos + separatorSize, reporterSpec.size() ); + fileNameSeparatorPos + separatorSize, reporterSpec.size() ); } auto result = factories.find( reporterName ); diff --git a/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp b/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp index 2210a3a4..53fc08b8 100644 --- a/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp +++ b/tests/SelfTest/IntrospectiveTests/CmdLine.tests.cpp @@ -682,3 +682,20 @@ TEST_CASE("Test with special, characters \"in name", "[cli][regression]") { // This test case succeeds if we can invoke it from the CLI SUCCEED(); } + +TEST_CASE("Various suspicious reporter specs are rejected", + "[cli][reporter-spec][approvals]") { + Catch::ConfigData config; + auto cli = Catch::makeCommandLineParser( config ); + + auto spec = GENERATE( as{}, + "", + "::console", + "console::", + "console::some-file::", + "::console::some-file::" ); + CAPTURE( spec ); + + auto result = cli.parse( { "test", "--reporter", spec } ); + REQUIRE_FALSE( result ); +}