mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
CommandLineInterface: Update control flow to accommodate the new way of reporting errors
This commit is contained in:
parent
e829bcd933
commit
c8380c25bb
@ -404,7 +404,7 @@ void CommandLineInterface::handleGasEstimation(string const& _contract)
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandLineInterface::readInputFiles()
|
||||
void CommandLineInterface::readInputFiles()
|
||||
{
|
||||
solAssert(!m_standardJsonInput.has_value(), "");
|
||||
|
||||
@ -413,7 +413,7 @@ bool CommandLineInterface::readInputFiles()
|
||||
m_options.input.mode == InputMode::License ||
|
||||
m_options.input.mode == InputMode::Version
|
||||
)
|
||||
return true;
|
||||
return;
|
||||
|
||||
m_fileReader.setBasePath(m_options.input.basePath);
|
||||
|
||||
@ -501,8 +501,6 @@ bool CommandLineInterface::readInputFiles()
|
||||
|
||||
if (m_fileReader.sourceCodes().empty() && !m_standardJsonInput.has_value())
|
||||
solThrow(CommandLineValidationError, "All specified input files either do not exist or are not regular files.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
map<string, Json::Value> CommandLineInterface::parseAstFromInput()
|
||||
@ -568,6 +566,30 @@ void CommandLineInterface::createJson(string const& _fileName, string const& _js
|
||||
createFile(boost::filesystem::basename(_fileName) + string(".json"), _json);
|
||||
}
|
||||
|
||||
bool CommandLineInterface::run(int _argc, char const* const* _argv)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!parseArguments(_argc, _argv))
|
||||
return false;
|
||||
|
||||
readInputFiles();
|
||||
processInput();
|
||||
return true;
|
||||
}
|
||||
catch (CommandLineError const& _exception)
|
||||
{
|
||||
m_hasOutput = true;
|
||||
|
||||
// There might be no message in the exception itself if the error output is bulky and has
|
||||
// already been printed to stderr (this happens e.g. for compiler errors).
|
||||
if (_exception.what() != ""s)
|
||||
serr() << _exception.what() << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
||||
{
|
||||
CommandLineParser parser;
|
||||
@ -581,22 +603,13 @@ bool CommandLineInterface::parseArguments(int _argc, char const* const* _argv)
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
parser.parse(_argc, _argv);
|
||||
}
|
||||
catch (CommandLineValidationError const& _exception)
|
||||
{
|
||||
serr() << _exception.what() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
parser.parse(_argc, _argv);
|
||||
m_options = parser.options();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::processInput()
|
||||
void CommandLineInterface::processInput()
|
||||
{
|
||||
switch (m_options.input.mode)
|
||||
{
|
||||
@ -619,18 +632,15 @@ bool CommandLineInterface::processInput()
|
||||
break;
|
||||
}
|
||||
case InputMode::Assembler:
|
||||
if (!assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine))
|
||||
return false;
|
||||
assemble(m_options.assembly.inputLanguage, m_options.assembly.targetMachine);
|
||||
break;
|
||||
case InputMode::Linker:
|
||||
if (!link())
|
||||
return false;
|
||||
link();
|
||||
writeLinkedFiles();
|
||||
break;
|
||||
case InputMode::Compiler:
|
||||
case InputMode::CompilerWithASTImport:
|
||||
if (!compile())
|
||||
return false;
|
||||
compile();
|
||||
outputCompilationResults();
|
||||
}
|
||||
|
||||
@ -651,7 +661,7 @@ void CommandLineInterface::printLicense()
|
||||
sout() << licenseText << endl;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::compile()
|
||||
void CommandLineInterface::compile()
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
||||
|
||||
@ -714,6 +724,8 @@ bool CommandLineInterface::compile()
|
||||
}
|
||||
catch (Exception const& _exc)
|
||||
{
|
||||
// FIXME: AST import is missing proper validations. This hack catches failing
|
||||
// assertions and presents them as if they were compiler errors.
|
||||
solThrow(CommandLineExecutionError, "Failed to import AST: "s + _exc.what());
|
||||
}
|
||||
}
|
||||
@ -754,8 +766,6 @@ bool CommandLineInterface::compile()
|
||||
solThrow(CommandLineExecutionError, "");
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineInterface::handleCombinedJSON()
|
||||
@ -884,7 +894,7 @@ void CommandLineInterface::handleAst()
|
||||
}
|
||||
}
|
||||
|
||||
bool CommandLineInterface::link()
|
||||
void CommandLineInterface::link()
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Linker, "");
|
||||
|
||||
@ -945,8 +955,6 @@ bool CommandLineInterface::link()
|
||||
src.second.resize(src.second.size() - 1);
|
||||
}
|
||||
m_fileReader.setSources(move(sourceCodes));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineInterface::writeLinkedFiles()
|
||||
@ -986,7 +994,7 @@ string CommandLineInterface::objectWithLinkRefsHex(evmasm::LinkerObject const& _
|
||||
return out;
|
||||
}
|
||||
|
||||
bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine)
|
||||
void CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine)
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Assembler, "");
|
||||
|
||||
@ -1090,8 +1098,6 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
|
||||
serr() << "No text representation found." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CommandLineInterface::outputCompilationResults()
|
||||
@ -1128,13 +1134,9 @@ void CommandLineInterface::outputCompilationResults()
|
||||
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
||||
|
||||
if (!m_options.output.dir.empty())
|
||||
{
|
||||
createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
sout() << "EVM assembly:" << endl << ret << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_options.compiler.estimateGas)
|
||||
|
@ -51,12 +51,28 @@ public:
|
||||
m_options(_options)
|
||||
{}
|
||||
|
||||
/// Parse command line arguments and return false if we should not continue
|
||||
/// Parses command-line arguments, executes the requested operation and handles validation and
|
||||
/// execution errors.
|
||||
/// @returns false if it catches a @p CommandLineValidationError or if the application is
|
||||
/// expected to exit with a non-zero exit code despite there being no error.
|
||||
bool run(int _argc, char const* const* _argv);
|
||||
|
||||
/// Parses command line arguments and stores the result in @p m_options.
|
||||
/// @throws CommandLineValidationError if command-line arguments are invalid.
|
||||
/// @returns false if the application is expected to exit with a non-zero exit code despite
|
||||
/// there being no error.
|
||||
bool parseArguments(int _argc, char const* const* _argv);
|
||||
/// Read the content of all input files and initialize the file reader.
|
||||
bool readInputFiles();
|
||||
/// Parse the files, create source code objects, print the output.
|
||||
bool processInput();
|
||||
|
||||
/// Reads the content of all input files and initializes the file reader.
|
||||
/// @throws CommandLineValidationError if it fails to read the input files (invalid paths,
|
||||
/// non-existent files, not enough or too many input files, etc.).
|
||||
void readInputFiles();
|
||||
|
||||
/// Executes the requested operation (compilation, assembling, standard JSON, etc.) and prints
|
||||
/// results to the terminal.
|
||||
/// @throws CommandLineExecutionError if execution fails due to errors in the input files.
|
||||
/// @throws CommandLineOutputError if creating output files or writing to them fails.
|
||||
void processInput();
|
||||
|
||||
CommandLineOptions const& options() const { return m_options; }
|
||||
FileReader const& fileReader() const { return m_fileReader; }
|
||||
@ -65,15 +81,15 @@ public:
|
||||
private:
|
||||
void printVersion();
|
||||
void printLicense();
|
||||
bool compile();
|
||||
bool link();
|
||||
void compile();
|
||||
void link();
|
||||
void writeLinkedFiles();
|
||||
/// @returns the ``// <identifier> -> name`` hint for library placeholders.
|
||||
static std::string libraryPlaceholderHint(std::string const& _libraryName);
|
||||
/// @returns the full object with library placeholder hints in hex.
|
||||
static std::string objectWithLinkRefsHex(evmasm::LinkerObject const& _obj);
|
||||
|
||||
bool assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine);
|
||||
void assemble(yul::AssemblyStack::Language _language, yul::AssemblyStack::Machine _targetMachine);
|
||||
|
||||
void outputCompilationResults();
|
||||
|
||||
|
@ -62,12 +62,7 @@ int main(int argc, char** argv)
|
||||
{
|
||||
setDefaultOrCLocale();
|
||||
solidity::frontend::CommandLineInterface cli(cin, cout, cerr);
|
||||
bool success =
|
||||
cli.parseArguments(argc, argv) &&
|
||||
cli.readInputFiles() &&
|
||||
cli.processInput();
|
||||
|
||||
return success ? 0 : 1;
|
||||
return cli.run(argc, argv) ? 0 : 1;
|
||||
}
|
||||
catch (smtutil::SMTLogicError const& _exception)
|
||||
{
|
||||
|
@ -19,6 +19,7 @@
|
||||
/// Unit tests for solc/CommandLineInterface.h
|
||||
|
||||
#include <solc/CommandLineInterface.h>
|
||||
#include <solc/Exceptions.h>
|
||||
|
||||
#include <test/solc/Common.h>
|
||||
|
||||
@ -114,7 +115,7 @@ BOOST_AUTO_TEST_SUITE(CommandLineInterfaceTest)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(help)
|
||||
{
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--help"}, "", /* _processInput */ true);
|
||||
OptionsReaderAndMessages result = runCLI({"solc", "--help"}, "");
|
||||
|
||||
BOOST_TEST(result.success);
|
||||
BOOST_TEST(boost::starts_with(result.stdoutContent, "solc, the Solidity commandline compiler."));
|
||||
@ -124,7 +125,7 @@ BOOST_AUTO_TEST_CASE(help)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(license)
|
||||
{
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--license"}, "", /* _processInput */ true);
|
||||
OptionsReaderAndMessages result = runCLI({"solc", "--license"}, "");
|
||||
|
||||
BOOST_TEST(result.success);
|
||||
BOOST_TEST(boost::starts_with(result.stdoutContent, "Most of the code is licensed under GPLv3"));
|
||||
@ -134,7 +135,7 @@ BOOST_AUTO_TEST_CASE(license)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(version)
|
||||
{
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", "--version"}, "", /* _processInput */ true);
|
||||
OptionsReaderAndMessages result = runCLI({"solc", "--version"}, "");
|
||||
|
||||
BOOST_TEST(result.success);
|
||||
BOOST_TEST(boost::ends_with(result.stdoutContent, "Version: " + solidity::frontend::VersionString + "\n"));
|
||||
@ -158,17 +159,16 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes)
|
||||
string expectedMessage =
|
||||
"The following options are mutually exclusive: "
|
||||
"--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. "
|
||||
"Select at most one.\n";
|
||||
"Select at most one.";
|
||||
|
||||
for (string const& mode1: inputModeOptions)
|
||||
for (string const& mode2: inputModeOptions)
|
||||
if (mode1 != mode2)
|
||||
{
|
||||
vector<string> commandLine = {"solc", mode1, mode2};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
}
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", mode1, mode2}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cli_input)
|
||||
@ -253,7 +253,7 @@ BOOST_AUTO_TEST_CASE(cli_ignore_missing_no_files_exist)
|
||||
"\"" + (tempDir.path() / "input2.sol").string() + "\" is not found. Skipping.\n"
|
||||
"All specified input files either do not exist or are not regular files.\n";
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({
|
||||
OptionsReaderAndMessages result = runCLI({
|
||||
"solc",
|
||||
(tempDir.path() / "input1.sol").string(),
|
||||
(tempDir.path() / "input2.sol").string(),
|
||||
@ -267,11 +267,13 @@ BOOST_AUTO_TEST_CASE(cli_not_a_file)
|
||||
{
|
||||
TemporaryDirectory tempDir(TEST_CASE_NAME);
|
||||
|
||||
string expectedMessage = "\"" + tempDir.path().string() + "\" is not a valid file.\n";
|
||||
string expectedMessage = "\"" + tempDir.path().string() + "\" is not a valid file.";
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({"solc", tempDir.path().string()});
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", tempDir.path().string()}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(standard_json_base_path)
|
||||
@ -336,24 +338,26 @@ BOOST_AUTO_TEST_CASE(standard_json_two_input_files)
|
||||
{
|
||||
string expectedMessage =
|
||||
"Too many input files for --standard-json.\n"
|
||||
"Please either specify a single file name or provide its content on standard input.\n";
|
||||
"Please either specify a single file name or provide its content on standard input.";
|
||||
|
||||
vector<string> commandLine = {"solc", "--standard-json", "input1.json", "input2.json"};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", "--standard-json", "input1.json", "input2.json"}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(standard_json_one_input_file_and_stdin)
|
||||
{
|
||||
string expectedMessage =
|
||||
"Too many input files for --standard-json.\n"
|
||||
"Please either specify a single file name or provide its content on standard input.\n";
|
||||
"Please either specify a single file name or provide its content on standard input.";
|
||||
|
||||
vector<string> commandLine = {"solc", "--standard-json", "input1.json", "-"};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", "--standard-json", "input1.json", "-"}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(standard_json_ignore_missing)
|
||||
@ -362,29 +366,31 @@ BOOST_AUTO_TEST_CASE(standard_json_ignore_missing)
|
||||
|
||||
// This option is pretty much useless Standard JSON mode.
|
||||
string expectedMessage =
|
||||
"\"" + (tempDir.path() / "input.json").string() + "\" is not found. Skipping.\n"
|
||||
"All specified input files either do not exist or are not regular files.\n";
|
||||
"All specified input files either do not exist or are not regular files.";
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles({
|
||||
"solc",
|
||||
"--standard-json",
|
||||
(tempDir.path() / "input.json").string(),
|
||||
"--ignore-missing",
|
||||
});
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({
|
||||
"solc",
|
||||
"--standard-json",
|
||||
(tempDir.path() / "input.json").string(),
|
||||
"--ignore-missing",
|
||||
}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(standard_json_remapping)
|
||||
{
|
||||
string expectedMessage =
|
||||
"Import remappings are not accepted on the command line in Standard JSON mode.\n"
|
||||
"Please put them under 'settings.remappings' in the JSON input.\n";
|
||||
"Please put them under 'settings.remappings' in the JSON input.";
|
||||
|
||||
vector<string> commandLine = {"solc", "--standard-json", "a=b"};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", "--standard-json", "a=b"}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cli_paths_to_source_unit_names_no_base_path)
|
||||
@ -997,11 +1003,7 @@ BOOST_AUTO_TEST_CASE(cli_include_paths)
|
||||
canonicalWorkDir / "lib",
|
||||
};
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(
|
||||
commandLine,
|
||||
"",
|
||||
true /* _processInput */
|
||||
);
|
||||
OptionsReaderAndMessages result = runCLI(commandLine, "");
|
||||
|
||||
BOOST_TEST(result.stderrContent == "");
|
||||
BOOST_TEST(result.stdoutContent == "");
|
||||
@ -1087,11 +1089,7 @@ BOOST_AUTO_TEST_CASE(standard_json_include_paths)
|
||||
|
||||
FileReader::FileSystemPathSet expectedAllowedDirectories = {};
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(
|
||||
commandLine,
|
||||
standardJsonInput,
|
||||
true /* _processInput */
|
||||
);
|
||||
OptionsReaderAndMessages result = runCLI(commandLine, standardJsonInput);
|
||||
|
||||
Json::Value parsedStdout;
|
||||
string jsonParsingErrors;
|
||||
@ -1119,18 +1117,19 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_empty_path)
|
||||
TemporaryWorkingDirectory tempWorkDir(tempDir);
|
||||
createFilesWithParentDirs({tempDir.path() / "base/main.sol"});
|
||||
|
||||
string expectedMessage = "Empty values are not allowed in --include-path.\n";
|
||||
string expectedMessage = "Empty values are not allowed in --include-path.";
|
||||
|
||||
vector<string> commandLine = {
|
||||
"solc",
|
||||
"--base-path=base/",
|
||||
"--include-path", "include/",
|
||||
"--include-path", "",
|
||||
"base/main.sol",
|
||||
};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({
|
||||
"solc",
|
||||
"--base-path=base/",
|
||||
"--include-path", "include/",
|
||||
"--include-path", "",
|
||||
"base/main.sol",
|
||||
}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cli_include_paths_without_base_path)
|
||||
@ -1139,12 +1138,13 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_without_base_path)
|
||||
TemporaryWorkingDirectory tempWorkDir(tempDir);
|
||||
createFilesWithParentDirs({tempDir.path() / "contract.sol"});
|
||||
|
||||
string expectedMessage = "--include-path option requires a non-empty base path.\n";
|
||||
string expectedMessage = "--include-path option requires a non-empty base path.";
|
||||
|
||||
vector<string> commandLine = {"solc", "--include-path", "include/", "contract.sol"};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(!result.success);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({"solc", "--include-path", "include/", "contract.sol"}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(cli_include_paths_should_detect_source_unit_name_collisions)
|
||||
@ -1173,35 +1173,37 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_should_detect_source_unit_name_collisions
|
||||
|
||||
{
|
||||
// import "contract1.sol" and import "contract2.sol" would be ambiguous:
|
||||
vector<string> commandLine = {
|
||||
"solc",
|
||||
"--base-path=dir1/",
|
||||
"--include-path=dir2/",
|
||||
"dir1/contract1.sol",
|
||||
"dir2/contract1.sol",
|
||||
"dir1/contract2.sol",
|
||||
"dir2/contract2.sol",
|
||||
};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_REQUIRE(!result.success);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({
|
||||
"solc",
|
||||
"--base-path=dir1/",
|
||||
"--include-path=dir2/",
|
||||
"dir1/contract1.sol",
|
||||
"dir2/contract1.sol",
|
||||
"dir1/contract2.sol",
|
||||
"dir2/contract2.sol",
|
||||
}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
// import "contract1.sol" and import "contract2.sol" would be ambiguous:
|
||||
vector<string> commandLine = {
|
||||
"solc",
|
||||
"--base-path=dir3/",
|
||||
"--include-path=dir1/",
|
||||
"--include-path=dir2/",
|
||||
"dir1/contract1.sol",
|
||||
"dir2/contract1.sol",
|
||||
"dir1/contract2.sol",
|
||||
"dir2/contract2.sol",
|
||||
};
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(commandLine);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_REQUIRE(!result.success);
|
||||
BOOST_CHECK_EXCEPTION(
|
||||
parseCommandLineAndReadInputFiles({
|
||||
"solc",
|
||||
"--base-path=dir3/",
|
||||
"--include-path=dir1/",
|
||||
"--include-path=dir2/",
|
||||
"dir1/contract1.sol",
|
||||
"dir2/contract1.sol",
|
||||
"dir1/contract2.sol",
|
||||
"dir2/contract2.sol",
|
||||
}),
|
||||
CommandLineValidationError,
|
||||
[&](auto const& _exception) { BOOST_TEST(_exception.what() == expectedMessage); return true; }
|
||||
);
|
||||
}
|
||||
|
||||
{
|
||||
@ -1316,12 +1318,7 @@ BOOST_AUTO_TEST_CASE(cli_include_paths_ambiguous_import)
|
||||
"3 | import \"contract.sol\";\n"
|
||||
" | ^^^^^^^^^^^^^^^^^^^^^^\n\n";
|
||||
|
||||
OptionsReaderAndMessages result = parseCommandLineAndReadInputFiles(
|
||||
commandLine,
|
||||
mainContractSource,
|
||||
true /* _processInput */
|
||||
);
|
||||
|
||||
OptionsReaderAndMessages result = runCLI(commandLine, mainContractSource);
|
||||
BOOST_TEST(result.stderrContent == expectedMessage);
|
||||
BOOST_REQUIRE(!result.success);
|
||||
}
|
||||
|
@ -95,11 +95,7 @@ ImportCheck checkImport(
|
||||
"pragma solidity >=0.0;\n" +
|
||||
_import + ";";
|
||||
|
||||
test::OptionsReaderAndMessages cliResult = test::parseCommandLineAndReadInputFiles(
|
||||
commandLine,
|
||||
standardInputContent,
|
||||
true /* processInput */
|
||||
);
|
||||
test::OptionsReaderAndMessages cliResult = test::runCLI(commandLine, standardInputContent);
|
||||
if (cliResult.success)
|
||||
return ImportCheck::OK();
|
||||
|
||||
|
@ -41,18 +41,34 @@ vector<char const*> test::makeArgv(vector<string> const& _commandLine)
|
||||
|
||||
test::OptionsReaderAndMessages test::parseCommandLineAndReadInputFiles(
|
||||
vector<string> const& _commandLine,
|
||||
string const& _standardInputContent,
|
||||
bool _processInput
|
||||
string const& _standardInputContent
|
||||
)
|
||||
{
|
||||
vector<char const*> argv = makeArgv(_commandLine);
|
||||
stringstream sin(_standardInputContent), sout, serr;
|
||||
CommandLineInterface cli(sin, sout, serr);
|
||||
bool success = cli.parseArguments(static_cast<int>(_commandLine.size()), argv.data());
|
||||
if (success)
|
||||
success = cli.readInputFiles();
|
||||
if (success && _processInput)
|
||||
success = cli.processInput();
|
||||
cli.readInputFiles();
|
||||
|
||||
return {
|
||||
success,
|
||||
cli.options(),
|
||||
cli.fileReader(),
|
||||
cli.standardJsonInput(),
|
||||
sout.str(),
|
||||
stripPreReleaseWarning(serr.str()),
|
||||
};
|
||||
}
|
||||
|
||||
test::OptionsReaderAndMessages test::runCLI(
|
||||
vector<string> const& _commandLine,
|
||||
string const& _standardInputContent
|
||||
)
|
||||
{
|
||||
vector<char const*> argv = makeArgv(_commandLine);
|
||||
stringstream sin(_standardInputContent), sout, serr;
|
||||
CommandLineInterface cli(sin, sout, serr);
|
||||
bool success = cli.run(static_cast<int>(_commandLine.size()), argv.data());
|
||||
|
||||
return {
|
||||
success,
|
||||
|
@ -44,10 +44,26 @@ struct OptionsReaderAndMessages
|
||||
|
||||
std::vector<char const*> makeArgv(std::vector<std::string> const& _commandLine);
|
||||
|
||||
/// Runs only command-line parsing, without compilation, assembling or any other input processing.
|
||||
/// Lets through any @a CommandLineErrors throw by the CLI.
|
||||
/// Note: This uses the @a CommandLineInterface class and does not actually spawn a new process.
|
||||
/// @param _commandLine Arguments in the form of strings that would be specified on the command-line.
|
||||
/// You must specify the program name as the first item.
|
||||
/// @param _standardInputContent Content that the CLI will be able to read from its standard input.
|
||||
OptionsReaderAndMessages parseCommandLineAndReadInputFiles(
|
||||
std::vector<std::string> const& _commandLine,
|
||||
std::string const& _standardInputContent = "",
|
||||
bool _processInput = false
|
||||
std::string const& _standardInputContent = ""
|
||||
);
|
||||
|
||||
/// Runs all stages of command-line interface processing, including error handling.
|
||||
/// Never throws @a CommandLineError - validation errors are included in the returned stderr content.
|
||||
/// Note: This uses the @a CommandLineInterface class and does not actually spawn a new process.
|
||||
/// @param _commandLine Arguments in the form of strings that would be specified on the command-line.
|
||||
/// You must specify the program name as the first item.
|
||||
/// @param _standardInputContent Content that the CLI will be able to read from its standard input.
|
||||
OptionsReaderAndMessages runCLI(
|
||||
std::vector<std::string> const& _commandLine,
|
||||
std::string const& _standardInputContent = ""
|
||||
);
|
||||
|
||||
std::string stripPreReleaseWarning(std::string const& _stderrContent);
|
||||
|
Loading…
Reference in New Issue
Block a user