Merge pull request #12118 from ethereum/separate-input-modes-for-help-license-version

Separate input modes for `--help`,  `--license` and `--version`
This commit is contained in:
Kamil Śliwak 2021-11-03 12:52:47 +01:00 committed by GitHub
commit 2d45099a87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 164 additions and 129 deletions

View File

@ -23,6 +23,7 @@
*/ */
#include <solc/CommandLineInterface.h> #include <solc/CommandLineInterface.h>
#include "license.h"
#include "solidity/BuildInfo.h" #include "solidity/BuildInfo.h"
#include <libsolidity/interface/Version.h> #include <libsolidity/interface/Version.h>
@ -405,6 +406,13 @@ bool CommandLineInterface::readInputFiles()
{ {
solAssert(!m_standardJsonInput.has_value(), ""); solAssert(!m_standardJsonInput.has_value(), "");
if (
m_options.input.mode == InputMode::Help ||
m_options.input.mode == InputMode::License ||
m_options.input.mode == InputMode::Version
)
return true;
m_fileReader.setBasePath(m_options.input.basePath); m_fileReader.setBasePath(m_options.input.basePath);
if (m_fileReader.basePath() != "") if (m_fileReader.basePath() != "")
@ -573,8 +581,18 @@ void CommandLineInterface::createJson(string const& _fileName, string const& _js
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv) bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
{ {
CommandLineParser parser(sout(/* _markAsUsed */ false), serr(/* _markAsUsed */ false)); CommandLineParser parser(serr(/* _markAsUsed */ false));
bool success = parser.parse(_argc, _argv, isatty(fileno(stdin)));
if (isatty(fileno(stdin)) && _argc == 1)
{
// If the terminal is taking input from the user, provide more user-friendly output.
CommandLineParser::printHelp(sout());
// In this case we want to exit with an error but not display any error message.
return false;
}
bool success = parser.parse(_argc, _argv);
if (!success) if (!success)
return false; return false;
m_hasOutput = m_hasOutput || parser.hasOutput(); m_hasOutput = m_hasOutput || parser.hasOutput();
@ -587,6 +605,15 @@ bool CommandLineInterface::processInput()
{ {
switch (m_options.input.mode) switch (m_options.input.mode)
{ {
case InputMode::Help:
CommandLineParser::printHelp(sout());
break;
case InputMode::License:
printLicense();
break;
case InputMode::Version:
printVersion();
break;
case InputMode::StandardJson: case InputMode::StandardJson:
{ {
solAssert(m_standardJsonInput.has_value(), ""); solAssert(m_standardJsonInput.has_value(), "");
@ -594,21 +621,38 @@ bool CommandLineInterface::processInput()
StandardCompiler compiler(m_fileReader.reader(), m_options.formatting.json); StandardCompiler compiler(m_fileReader.reader(), m_options.formatting.json);
sout() << compiler.compile(move(m_standardJsonInput.value())) << endl; sout() << compiler.compile(move(m_standardJsonInput.value())) << endl;
m_standardJsonInput.reset(); m_standardJsonInput.reset();
return true; break;
} }
case InputMode::Assembler: case InputMode::Assembler:
{ if (!assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine))
return assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine); return false;
} break;
case InputMode::Linker: case InputMode::Linker:
return link(); if (!link())
return false;
writeLinkedFiles();
break;
case InputMode::Compiler: case InputMode::Compiler:
case InputMode::CompilerWithASTImport: case InputMode::CompilerWithASTImport:
return compile(); if (!compile())
return false;
outputCompilationResults();
} }
solAssert(false, ""); return !m_outputFailed;
return false; }
void CommandLineInterface::printVersion()
{
sout() << "solc, the solidity compiler commandline interface" << endl;
sout() << "Version: " << solidity::frontend::VersionString << endl;
}
void CommandLineInterface::printLicense()
{
sout() << otherLicenses << endl;
// This is a static variable generated by cmake from LICENSE.txt
sout() << licenseText << endl;
} }
bool CommandLineInterface::compile() bool CommandLineInterface::compile()
@ -843,21 +887,6 @@ void CommandLineInterface::handleAst()
} }
} }
bool CommandLineInterface::actOnInput()
{
if (m_options.input.mode == InputMode::StandardJson || m_options.input.mode == InputMode::Assembler)
// Already done in "processInput" phase.
return true;
else if (m_options.input.mode == InputMode::Linker)
writeLinkedFiles();
else
{
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
outputCompilationResults();
}
return !m_outputFailed;
}
bool CommandLineInterface::link() bool CommandLineInterface::link()
{ {
solAssert(m_options.input.mode == InputMode::Linker, ""); solAssert(m_options.input.mode == InputMode::Linker, "");

View File

@ -55,17 +55,16 @@ public:
bool parseArguments(int _argc, char const* const* _argv); bool parseArguments(int _argc, char const* const* _argv);
/// Read the content of all input files and initialize the file reader. /// Read the content of all input files and initialize the file reader.
bool readInputFiles(); bool readInputFiles();
/// Parse the files and create source code objects /// Parse the files, create source code objects, print the output.
bool processInput(); bool processInput();
/// Perform actions on the input depending on provided compiler arguments
/// @returns true on success.
bool actOnInput();
CommandLineOptions const& options() const { return m_options; } CommandLineOptions const& options() const { return m_options; }
FileReader const& fileReader() const { return m_fileReader; } FileReader const& fileReader() const { return m_fileReader; }
std::optional<std::string> const& standardJsonInput() const { return m_standardJsonInput; } std::optional<std::string> const& standardJsonInput() const { return m_standardJsonInput; }
private: private:
void printVersion();
void printLicense();
bool compile(); bool compile();
bool link(); bool link();
void writeLinkedFiles(); void writeLinkedFiles();

View File

@ -16,8 +16,6 @@
*/ */
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
#include "license.h"
#include <solc/CommandLineParser.h> #include <solc/CommandLineParser.h>
#include <libyul/optimiser/Suite.h> #include <libyul/optimiser/Suite.h>
#include <liblangutil/EVMVersion.h> #include <liblangutil/EVMVersion.h>
@ -36,19 +34,12 @@ namespace po = boost::program_options;
namespace solidity::frontend namespace solidity::frontend
{ {
ostream& CommandLineParser::sout()
{
m_hasOutput = true;
return m_sout;
}
ostream& CommandLineParser::serr() ostream& CommandLineParser::serr()
{ {
m_hasOutput = true; m_hasOutput = true;
return m_serr; return m_serr;
} }
#define cout
#define cerr #define cerr
static string const g_strAllowPaths = "allow-paths"; static string const g_strAllowPaths = "allow-paths";
@ -147,26 +138,6 @@ static map<InputMode, string> const g_inputModeName = {
{InputMode::Linker, "linker"}, {InputMode::Linker, "linker"},
}; };
void CommandLineParser::printVersionAndExit()
{
sout() <<
"solc, the solidity compiler commandline interface" <<
endl <<
"Version: " <<
solidity::frontend::VersionString <<
endl;
exit(EXIT_SUCCESS);
}
void CommandLineParser::printLicenseAndExit()
{
sout() << otherLicenses << endl;
// This is a static variable generated by cmake from LICENSE.txt
sout() << licenseText << endl;
exit(EXIT_SUCCESS);
}
bool CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames) bool CommandLineParser::checkMutuallyExclusive(vector<string> const& _optionNames)
{ {
if (countEnabledOptions(_optionNames) > 1) if (countEnabledOptions(_optionNames) > 1)
@ -297,11 +268,11 @@ OptimiserSettings CommandLineOptions::optimiserSettings() const
return settings; return settings;
} }
bool CommandLineParser::parse(int _argc, char const* const* _argv, bool _interactiveTerminal) bool CommandLineParser::parse(int _argc, char const* const* _argv)
{ {
m_hasOutput = false; m_hasOutput = false;
if (!parseArgs(_argc, _argv, _interactiveTerminal)) if (!parseArgs(_argc, _argv))
return false; return false;
return processArgs(); return processArgs();
@ -482,6 +453,10 @@ bool CommandLineParser::parseOutputSelection()
switch (_mode) switch (_mode)
{ {
case InputMode::Help:
case InputMode::License:
case InputMode::Version:
solAssert(false);
case InputMode::Compiler: case InputMode::Compiler:
case InputMode::CompilerWithASTImport: case InputMode::CompilerWithASTImport:
return contains(compilerModeOutputs, _outputName); return contains(compilerModeOutputs, _outputName);
@ -847,7 +822,7 @@ po::positional_options_description CommandLineParser::positionalOptionsDescripti
return filesPositions; return filesPositions;
} }
bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal) bool CommandLineParser::parseArgs(int _argc, char const* const* _argv)
{ {
po::options_description allOptions = optionsDescription(); po::options_description allOptions = optionsDescription();
po::positional_options_description filesPositions = positionalOptionsDescription(); po::positional_options_description filesPositions = positionalOptionsDescription();
@ -866,18 +841,6 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _int
return false; return false;
} }
if (m_args.count(g_strHelp) || (_interactiveTerminal && _argc == 1))
{
sout() << allOptions;
return false;
}
if (m_args.count(g_strVersion))
printVersionAndExit();
if (m_args.count(g_strLicense))
printLicenseAndExit();
po::notify(m_args); po::notify(m_args);
return true; return true;
@ -886,6 +849,9 @@ bool CommandLineParser::parseArgs(int _argc, char const* const* _argv, bool _int
bool CommandLineParser::processArgs() bool CommandLineParser::processArgs()
{ {
if (!checkMutuallyExclusive({ if (!checkMutuallyExclusive({
g_strHelp,
g_strLicense,
g_strVersion,
g_strStandardJSON, g_strStandardJSON,
g_strLink, g_strLink,
g_strAssemble, g_strAssemble,
@ -895,7 +861,13 @@ bool CommandLineParser::processArgs()
})) }))
return false; return false;
if (m_args.count(g_strStandardJSON) > 0) if (m_args.count(g_strHelp) > 0)
m_options.input.mode = InputMode::Help;
else if (m_args.count(g_strLicense) > 0)
m_options.input.mode = InputMode::License;
else if (m_args.count(g_strVersion) > 0)
m_options.input.mode = InputMode::Version;
else if (m_args.count(g_strStandardJSON) > 0)
m_options.input.mode = InputMode::StandardJson; m_options.input.mode = InputMode::StandardJson;
else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0) else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0)
m_options.input.mode = InputMode::Assembler; m_options.input.mode = InputMode::Assembler;
@ -906,6 +878,13 @@ bool CommandLineParser::processArgs()
else else
m_options.input.mode = InputMode::Compiler; m_options.input.mode = InputMode::Compiler;
if (
m_options.input.mode == InputMode::Help ||
m_options.input.mode == InputMode::License ||
m_options.input.mode == InputMode::Version
)
return true;
map<string, set<InputMode>> validOptionInputModeCombinations = { map<string, set<InputMode>> validOptionInputModeCombinations = {
// TODO: This should eventually contain all options. // TODO: This should eventually contain all options.
{g_strErrorRecovery, {InputMode::Compiler, InputMode::CompilerWithASTImport}}, {g_strErrorRecovery, {InputMode::Compiler, InputMode::CompilerWithASTImport}},

View File

@ -48,6 +48,9 @@ namespace solidity::frontend
enum class InputMode enum class InputMode
{ {
Help,
License,
Version,
Compiler, Compiler,
CompilerWithASTImport, CompilerWithASTImport,
StandardJson, StandardJson,
@ -230,34 +233,28 @@ struct CommandLineOptions
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure. /// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
/// Validates provided values and prints error messages in case of errors. /// Validates provided values and prints error messages in case of errors.
///
/// The class is also responsible for handling options that only result in printing informational
/// text, without the need to invoke the compiler - printing usage banner, version or license.
class CommandLineParser class CommandLineParser
{ {
public: public:
explicit CommandLineParser(std::ostream& _sout, std::ostream& _serr): explicit CommandLineParser(std::ostream& _serr):
m_sout(_sout),
m_serr(_serr) m_serr(_serr)
{} {}
/// Parses the command-line arguments and fills out the internal CommandLineOptions structure. /// Parses the command-line arguments and fills out the internal CommandLineOptions structure.
/// Performs validation and prints error messages. If requested, prints usage banner, version /// Performs validation and prints error messages.
/// or license.
/// @param interactiveTerminal specifies whether the terminal is taking input from the user.
/// This is used to determine whether to provide more user-friendly output in some situations.
/// E.g. whether to print help text when no arguments are provided.
/// @return true if there were no validation errors when parsing options and the /// @return true if there were no validation errors when parsing options and the
/// CommandLineOptions structure has been fully initialized. false if there were errors - in /// CommandLineOptions structure has been fully initialized. false if there were errors - in
/// this case CommandLineOptions may be only partially filled out. May also return false if /// this case CommandLineOptions may be only partially filled out. May also return false if
/// there is not further processing necessary and the program should just exit. /// there is not further processing necessary and the program should just exit.
bool parse(int _argc, char const* const* _argv, bool _interactiveTerminal); bool parse(int _argc, char const* const* _argv);
CommandLineOptions const& options() const { return m_options; } CommandLineOptions const& options() const { return m_options; }
/// Returns true if the parser has written anything to any of its output streams. /// Returns true if the parser has written anything to any of its output streams.
bool hasOutput() const { return m_hasOutput; } bool hasOutput() const { return m_hasOutput; }
static void printHelp(std::ostream& _out) { _out << optionsDescription(); }
private: private:
/// @returns a specification of all named command-line options accepted by the compiler. /// @returns a specification of all named command-line options accepted by the compiler.
/// The object can be used to parse command-line arguments or to generate the help screen. /// The object can be used to parse command-line arguments or to generate the help screen.
@ -270,7 +267,7 @@ private:
/// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args. /// Uses boost::program_options to parse the command-line arguments and leaves the result in @a m_args.
/// Also handles the arguments that result in information being printed followed by immediate exit. /// Also handles the arguments that result in information being printed followed by immediate exit.
/// @returns false if parsing fails due to syntactical errors or the arguments not matching the description. /// @returns false if parsing fails due to syntactical errors or the arguments not matching the description.
bool parseArgs(int _argc, char const* const* _argv, bool _interactiveTerminal); bool parseArgs(int _argc, char const* const* _argv);
/// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions /// Validates parsed arguments stored in @a m_args and fills out the internal CommandLineOptions
/// structure. /// structure.
@ -294,20 +291,13 @@ private:
bool parseOutputSelection(); bool parseOutputSelection();
bool checkMutuallyExclusive(std::vector<std::string> const& _optionNames); bool checkMutuallyExclusive(std::vector<std::string> const& _optionNames);
[[noreturn]] void printVersionAndExit();
[[noreturn]] void printLicenseAndExit();
size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const; size_t countEnabledOptions(std::vector<std::string> const& _optionNames) const;
static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", "); static std::string joinOptionNames(std::vector<std::string> const& _optionNames, std::string _separator = ", ");
/// Returns the stream that should receive normal output. Sets m_hasOutput to true if the
/// stream has ever been used.
std::ostream& sout();
/// Returns the stream that should receive error output. Sets m_hasOutput to true if the /// Returns the stream that should receive error output. Sets m_hasOutput to true if the
/// stream has ever been used. /// stream has ever been used.
std::ostream& serr(); std::ostream& serr();
std::ostream& m_sout;
std::ostream& m_serr; std::ostream& m_serr;
bool m_hasOutput = false; bool m_hasOutput = false;

View File

@ -65,8 +65,7 @@ int main(int argc, char** argv)
bool success = bool success =
cli.parseArguments(argc, argv) && cli.parseArguments(argc, argv) &&
cli.readInputFiles() && cli.readInputFiles() &&
cli.processInput() && cli.processInput();
cli.actOnInput();
return success ? 0 : 1; return success ? 0 : 1;
} }

View File

@ -29,6 +29,8 @@
#include <libsolutil/JSON.h> #include <libsolutil/JSON.h>
#include <boost/algorithm/string.hpp>
#include <range/v3/view/transform.hpp> #include <range/v3/view/transform.hpp>
#include <map> #include <map>
@ -110,9 +112,42 @@ namespace solidity::frontend::test
BOOST_AUTO_TEST_SUITE(CommandLineInterfaceTest) BOOST_AUTO_TEST_SUITE(CommandLineInterfaceTest)
BOOST_AUTO_TEST_CASE(help)
{
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--help"}, "", /* _processInput */ true);
BOOST_TEST(result.success);
BOOST_TEST(boost::starts_with(result.stdoutContent, "solc, the Solidity commandline compiler."));
BOOST_TEST(result.stderrContent == "");
BOOST_TEST(result.options.input.mode == InputMode::Help);
}
BOOST_AUTO_TEST_CASE(license)
{
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--license"}, "", /* _processInput */ true);
BOOST_TEST(result.success);
BOOST_TEST(boost::starts_with(result.stdoutContent, "Most of the code is licensed under GPLv3"));
BOOST_TEST(result.stderrContent == "");
BOOST_TEST(result.options.input.mode == InputMode::License);
}
BOOST_AUTO_TEST_CASE(version)
{
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--version"}, "", /* _processInput */ true);
BOOST_TEST(result.success);
BOOST_TEST(boost::ends_with(result.stdoutContent, "Version: " + solidity::frontend::VersionString + "\n"));
BOOST_TEST(result.stderrContent == "");
BOOST_TEST(result.options.input.mode == InputMode::Version);
}
BOOST_AUTO_TEST_CASE(multiple_input_modes) BOOST_AUTO_TEST_CASE(multiple_input_modes)
{ {
array<string, 6> inputModeOptions = { array<string, 9> inputModeOptions = {
"--help",
"--license",
"--version",
"--standard-json", "--standard-json",
"--link", "--link",
"--assemble", "--assemble",
@ -122,7 +157,7 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes)
}; };
string expectedMessage = string expectedMessage =
"The following options are mutually exclusive: " "The following options are mutually exclusive: "
"--standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. " "--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. "
"Select at most one.\n"; "Select at most one.\n";
for (string const& mode1: inputModeOptions) for (string const& mode1: inputModeOptions)

View File

@ -30,8 +30,6 @@
#include <libsmtutil/SolverInterface.h> #include <libsmtutil/SolverInterface.h>
#include <libsolidity/interface/Version.h> #include <libsolidity/interface/Version.h>
#include <boost/algorithm/string.hpp>
#include <map> #include <map>
#include <optional> #include <optional>
#include <ostream> #include <ostream>
@ -48,16 +46,12 @@ using namespace solidity::yul;
namespace namespace
{ {
optional<CommandLineOptions> parseCommandLine(vector<string> const& _commandLine, ostream& _stdout, ostream& _stderr) optional<CommandLineOptions> parseCommandLine(vector<string> const& _commandLine, ostream& _stderr)
{ {
vector<char const*> argv = test::makeArgv(_commandLine); vector<char const*> argv = test::makeArgv(_commandLine);
CommandLineParser cliParser(_stdout, _stderr); CommandLineParser cliParser(_stderr);
bool success = cliParser.parse( bool success = cliParser.parse(static_cast<int>(_commandLine.size()), argv.data());
static_cast<int>(_commandLine.size()),
argv.data(),
false // interactiveTerminal
);
if (!success) if (!success)
return nullopt; return nullopt;
@ -81,24 +75,34 @@ BOOST_AUTO_TEST_CASE(no_options)
expectedOptions.modelChecker.initialize = true; expectedOptions.modelChecker.initialize = true;
expectedOptions.modelChecker.settings = {}; expectedOptions.modelChecker.settings = {};
stringstream sout, serr; stringstream serr;
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr); optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
BOOST_TEST(sout.str() == "");
BOOST_TEST(serr.str() == ""); BOOST_TEST(serr.str() == "");
BOOST_REQUIRE(parsedOptions.has_value()); BOOST_REQUIRE(parsedOptions.has_value());
BOOST_TEST(parsedOptions.value() == expectedOptions); BOOST_TEST(parsedOptions.value() == expectedOptions);
} }
BOOST_AUTO_TEST_CASE(help) BOOST_AUTO_TEST_CASE(help_license_version)
{ {
stringstream sout, serr; map<string, InputMode> expectedModePerOption = {
optional<CommandLineOptions> parsedOptions = parseCommandLine({"solc", "--help"}, sout, serr); {"--help", InputMode::Help},
{"--license", InputMode::License},
{"--version", InputMode::Version},
};
BOOST_TEST(serr.str() == ""); for (auto const& [option, expectedMode]: expectedModePerOption)
BOOST_TEST(boost::starts_with(sout.str(), "solc, the Solidity commandline compiler.")); {
BOOST_TEST(sout.str().find("Usage: solc [options] [input_file...]") != string::npos); stringstream serr;
BOOST_TEST(!parsedOptions.has_value()); optional<CommandLineOptions> parsedOptions = parseCommandLine({"solc", option}, serr);
CommandLineOptions expectedOptions;
expectedOptions.input.mode = expectedMode;
BOOST_TEST(serr.str() == "");
BOOST_REQUIRE(parsedOptions.has_value());
BOOST_TEST(parsedOptions.value() == expectedOptions);
}
} }
BOOST_AUTO_TEST_CASE(cli_mode_options) BOOST_AUTO_TEST_CASE(cli_mode_options)
@ -220,10 +224,9 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
5, 5,
}; };
stringstream sout, serr; stringstream serr;
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr); optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
BOOST_TEST(sout.str() == "");
BOOST_TEST(serr.str() == ""); BOOST_TEST(serr.str() == "");
BOOST_REQUIRE(parsedOptions.has_value()); BOOST_REQUIRE(parsedOptions.has_value());
BOOST_TEST(parsedOptions.value() == expectedOptions); BOOST_TEST(parsedOptions.value() == expectedOptions);
@ -337,10 +340,9 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
expectedOptions.optimizer.expectedExecutionsPerDeployment = 1000; expectedOptions.optimizer.expectedExecutionsPerDeployment = 1000;
} }
stringstream sout, serr; stringstream serr;
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr); optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
BOOST_TEST(sout.str() == "");
BOOST_TEST(serr.str() == "Warning: Yul is still experimental. Please use the output with care.\n"); BOOST_TEST(serr.str() == "Warning: Yul is still experimental. Please use the output with care.\n");
BOOST_REQUIRE(parsedOptions.has_value()); BOOST_REQUIRE(parsedOptions.has_value());
BOOST_TEST(parsedOptions.value() == expectedOptions); BOOST_TEST(parsedOptions.value() == expectedOptions);
@ -406,10 +408,9 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options)
expectedOptions.compiler.combinedJsonRequests->abi = true; expectedOptions.compiler.combinedJsonRequests->abi = true;
expectedOptions.compiler.combinedJsonRequests->binary = true; expectedOptions.compiler.combinedJsonRequests->binary = true;
stringstream sout, serr; stringstream serr;
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr); optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
BOOST_TEST(sout.str() == "");
BOOST_TEST(serr.str() == ""); BOOST_TEST(serr.str() == "");
BOOST_REQUIRE(parsedOptions.has_value()); BOOST_REQUIRE(parsedOptions.has_value());
BOOST_TEST(parsedOptions.value() == expectedOptions); BOOST_TEST(parsedOptions.value() == expectedOptions);
@ -426,11 +427,10 @@ BOOST_AUTO_TEST_CASE(invalid_options_input_modes_combinations)
for (auto const& [optionName, inputModes]: invalidOptionInputModeCombinations) for (auto const& [optionName, inputModes]: invalidOptionInputModeCombinations)
for (string const& inputMode: inputModes) for (string const& inputMode: inputModes)
{ {
stringstream sout, serr; stringstream serr;
vector<string> commandLine = {"solc", optionName, "file", inputMode}; vector<string> commandLine = {"solc", optionName, "file", inputMode};
optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, sout, serr); optional<CommandLineOptions> parsedOptions = parseCommandLine(commandLine, serr);
BOOST_TEST(sout.str() == "");
BOOST_TEST(serr.str() == "The following options are not supported in the current input mode: " + optionName + "\n"); BOOST_TEST(serr.str() == "The following options are not supported in the current input mode: " + optionName + "\n");
BOOST_REQUIRE(!parsedOptions.has_value()); BOOST_REQUIRE(!parsedOptions.has_value());
} }

View File

@ -70,6 +70,10 @@ string test::stripPreReleaseWarning(string const& _stderrContent)
R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)" R"(Warning( \(3805\))?: This is a pre-release compiler version, please do not use it in production\.\n)"
R"((\n)?)" R"((\n)?)"
}; };
static regex const noOutputRegex{
R"(Compiler run successful, no output requested\.\n)"
};
return regex_replace(_stderrContent, preReleaseWarningRegex, ""); string output = regex_replace(_stderrContent, preReleaseWarningRegex, "");
return regex_replace(move(output), noOutputRegex, "");
} }