From f4110b295b518b71114c070f91f191921d2fa80f Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 19 Feb 2019 13:24:04 +0100 Subject: [PATCH 1/3] Use env variable to get IPC path for isoltest --- test/Common.cpp | 5 ++++- test/Common.h | 5 +++-- test/Options.cpp | 6 +----- test/tools/isoltest.cpp | 4 +++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/test/Common.cpp b/test/Common.cpp index a80c55d4c..7a9334e4e 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -26,8 +26,11 @@ namespace dev namespace test { -boost::filesystem::path discoverTestPath() +boost::filesystem::path getTestPath() { + if (auto path = getenv("ETH_TEST_PATH")) + return path; + auto const searchPath = { fs::current_path() / ".." / ".." / ".." / "test", diff --git a/test/Common.h b/test/Common.h index e87faa0e6..a3b1ada32 100644 --- a/test/Common.h +++ b/test/Common.h @@ -24,12 +24,13 @@ namespace dev namespace test { -/// Tries to find a path that contains the directories "libsolidity/syntaxTests" +/// First checks the environment variable ETH_TEST_PATH. If empty, +/// tries to find a path that contains the directories "libsolidity/syntaxTests" /// and returns it if found. /// The routine searches in the current directory, and inside the "test" directory /// starting from the current directory and up to three levels up. /// @returns the path of the first match or an empty path if not found. -boost::filesystem::path discoverTestPath(); +boost::filesystem::path getTestPath(); } } diff --git a/test/Options.cpp b/test/Options.cpp index 8389d853b..23de9cc55 100644 --- a/test/Options.cpp +++ b/test/Options.cpp @@ -74,11 +74,7 @@ Options::Options() ipcPath = path; if (testPath.empty()) - if (auto path = getenv("ETH_TEST_PATH")) - testPath = path; - - if (testPath.empty()) - testPath = discoverTestPath(); + testPath = getTestPath(); } void Options::validate() const diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index 1d3b9eda9..ceeef2906 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -336,6 +336,7 @@ int main(int argc, char *argv[]) bool disableIPC = false; bool disableSMT = false; bool formatted = true; + po::options_description options( R"(isoltest, tool for interactively managing test contracts. Usage: isoltest [Options] --ipcpath ipcpath @@ -344,6 +345,7 @@ Interactively validates test contracts. Allowed options)", po::options_description::m_default_line_length, po::options_description::m_default_line_length - 23); + options.add_options() ("help", "Show this help screen.") ("testpath", po::value(&testPath), "path to test files") @@ -396,7 +398,7 @@ Allowed options)", } if (testPath.empty()) - testPath = dev::test::discoverTestPath(); + testPath = dev::test::getTestPath(); TestStats global_stats{0, 0}; From 8b342cbe6a9aa2e32391e6e7fcc1e80a03fa931f Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 19 Feb 2019 13:24:24 +0100 Subject: [PATCH 2/3] Use Boost::Program_Options in soltest --- test/CMakeLists.txt | 2 +- test/Options.cpp | 67 ++++++++++++++++++++++++--------------------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index e231a6f97..59603442d 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -30,7 +30,7 @@ add_executable(soltest ${sources} ${headers} ${libsolidity_sources} ${libsolidity_headers} ${libsolidity_util_sources} ${libsolidity_util_headers} ) -target_link_libraries(soltest PRIVATE libsolc yul solidity evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(soltest PRIVATE libsolc yul solidity evmasm devcore ${Boost_PROGRAM_OPTIONS_LIBRARIES} ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) if (LLL) target_link_libraries(soltest PRIVATE lll) diff --git a/test/Options.cpp b/test/Options.cpp index 23de9cc55..1c46f8cf8 100644 --- a/test/Options.cpp +++ b/test/Options.cpp @@ -28,10 +28,12 @@ #include #include +#include using namespace std; using namespace dev::test; namespace fs = boost::filesystem; +namespace po = boost::program_options; Options const& Options::get() { @@ -42,39 +44,42 @@ Options const& Options::get() Options::Options() { auto const& suite = boost::unit_test::framework::master_test_suite(); - for (auto i = 0; i < suite.argc; i++) - if (string(suite.argv[i]) == "--ipcpath" && i + 1 < suite.argc) - { - ipcPath = suite.argv[i + 1]; - i++; - } - else if (string(suite.argv[i]) == "--testpath" && i + 1 < suite.argc) - { - testPath = suite.argv[i + 1]; - i++; - } - else if (string(suite.argv[i]) == "--optimize") - optimize = true; - else if (string(suite.argv[i]) == "--abiencoderv2") - useABIEncoderV2 = true; - else if (string(suite.argv[i]) == "--evm-version") - { - evmVersionString = i + 1 < suite.argc ? suite.argv[i + 1] : "INVALID"; - ++i; - } - else if (string(suite.argv[i]) == "--show-messages") - showMessages = true; - else if (string(suite.argv[i]) == "--no-ipc") - disableIPC = true; - else if (string(suite.argv[i]) == "--no-smt") - disableSMT = true; - if (!disableIPC && ipcPath.empty()) - if (auto path = getenv("ETH_TEST_IPC")) - ipcPath = path; + if (suite.argc == 0) + return; - if (testPath.empty()) - testPath = getTestPath(); + po::options_description options("", + po::options_description::m_default_line_length, + po::options_description::m_default_line_length - 23); + + options.add_options() + ("testpath", po::value(&testPath)->default_value(getTestPath()), "path to test files") + ("ipcpath", po::value(&ipcPath)->default_value(getenv("ETH_TEST_IPC")), "path to ipc socket") + ("no-ipc", po::bool_switch(&disableIPC), "disable semantic tests") + ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") + ("optimize", po::bool_switch(&optimize), "enables optimization") + ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") + ("evm-version", po::value(&evmVersionString), "which evm version to use") + ("show-messages", po::bool_switch(&showMessages), "enables message output"); + + po::variables_map arguments; + + po::command_line_parser cmdLineParser(suite.argc, suite.argv); + cmdLineParser.options(options); + po::store(cmdLineParser.run(), arguments); + po::notify(arguments); + + if (!disableIPC) + { + solAssert( + !ipcPath.empty(), + "No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used." + ); + solAssert( + fs::exists(ipcPath), + "Invalid ipc path specified." + ); + } } void Options::validate() const From 1672902abb65f922897435df1270846e0c7f958f Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Tue, 19 Feb 2019 17:34:59 +0100 Subject: [PATCH 3/3] Unify isoltest and soltest options code Also provide a default value for ipc-path, which is the same one as aleth uses. --- test/Common.cpp | 75 +++++++++++++++++++++++++++++++- test/Common.h | 31 +++++++++++--- test/ExecutionFramework.cpp | 2 +- test/Options.cpp | 42 ++---------------- test/Options.h | 13 ++---- test/boostTest.cpp | 2 +- test/tools/CMakeLists.txt | 1 + test/tools/IsolTestOptions.cpp | 74 ++++++++++++++++++++++++++++++++ test/tools/IsolTestOptions.h | 38 +++++++++++++++++ test/tools/isoltest.cpp | 78 +++++----------------------------- 10 files changed, 229 insertions(+), 127 deletions(-) create mode 100644 test/tools/IsolTestOptions.cpp create mode 100644 test/tools/IsolTestOptions.h diff --git a/test/Common.cpp b/test/Common.cpp index 7a9334e4e..5c21744b2 100644 --- a/test/Common.cpp +++ b/test/Common.cpp @@ -17,16 +17,25 @@ #include +#include #include +#include namespace fs = boost::filesystem; +namespace po = boost::program_options; namespace dev { namespace test { -boost::filesystem::path getTestPath() +/// If non-empty returns the value of the env. variable ETH_TEST_PATH, otherwise +/// it tries to find a path that contains the directories "libsolidity/syntaxTests" +/// and returns it if found. +/// The routine searches in the current directory, and inside the "test" directory +/// starting from the current directory and up to three levels up. +/// @returns the path of the first match or an empty path if not found. +boost::filesystem::path testPath() { if (auto path = getenv("ETH_TEST_PATH")) return path; @@ -48,6 +57,70 @@ boost::filesystem::path getTestPath() return {}; } +std::string IPCEnvOrDefaultPath() +{ + if (auto path = getenv("ETH_TEST_IPC")) + return path; + + if (auto home = getenv("HOME")) + return std::string(home) + "/.ethereum/geth.ipc"; + + return std::string{}; +} + +CommonOptions::CommonOptions(std::string _caption): + options(_caption, + po::options_description::m_default_line_length, + po::options_description::m_default_line_length - 23 + ) +{ + options.add_options() + ("testpath", po::value(&this->testPath)->default_value(dev::test::testPath()), "path to test files") + ("ipcpath", po::value(&ipcPath)->default_value(IPCEnvOrDefaultPath()), "path to ipc socket") + ("no-ipc", po::bool_switch(&disableIPC), "disable semantic tests") + ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker"); +} + +void CommonOptions::validate() const +{ + assertThrow( + !testPath.empty(), + ConfigException, + "No test path specified. The --testpath argument must not be empty when given." + ); + assertThrow( + fs::exists(testPath), + ConfigException, + "Invalid test path specified." + ); + + if (!disableIPC) + { + assertThrow( + !ipcPath.empty(), + ConfigException, + "No ipc path specified. The --ipcpath argument must not be empty when given." + ); + assertThrow( + fs::exists(ipcPath), + ConfigException, + "Invalid ipc path specified." + ); + } +} + +bool CommonOptions::parse(int argc, char const* const* argv) +{ + po::variables_map arguments; + + po::command_line_parser cmdLineParser(argc, argv); + cmdLineParser.options(options); + po::store(cmdLineParser.run(), arguments); + po::notify(arguments); + + return true; +} } + } diff --git a/test/Common.h b/test/Common.h index a3b1ada32..272db5a0f 100644 --- a/test/Common.h +++ b/test/Common.h @@ -17,20 +17,37 @@ #pragma once +#include + #include +#include +#include namespace dev { + namespace test { -/// First checks the environment variable ETH_TEST_PATH. If empty, -/// tries to find a path that contains the directories "libsolidity/syntaxTests" -/// and returns it if found. -/// The routine searches in the current directory, and inside the "test" directory -/// starting from the current directory and up to three levels up. -/// @returns the path of the first match or an empty path if not found. -boost::filesystem::path getTestPath(); +struct ConfigException : public Exception {}; + +struct CommonOptions: boost::noncopyable +{ + boost::filesystem::path ipcPath; + boost::filesystem::path testPath; + bool optimize = false; + bool disableIPC = false; + bool disableSMT = false; + + virtual bool parse(int argc, char const* const* argv); + // Throws a ConfigException on error + virtual void validate() const; + +protected: + CommonOptions(std::string caption = ""); + + boost::program_options::options_description options; +}; } } diff --git a/test/ExecutionFramework.cpp b/test/ExecutionFramework.cpp index ebb4e6bca..dcf61af66 100644 --- a/test/ExecutionFramework.cpp +++ b/test/ExecutionFramework.cpp @@ -40,7 +40,7 @@ h256 const EmptyTrie("0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5 string getIPCSocketPath() { - string ipcPath = dev::test::Options::get().ipcPath; + string ipcPath = dev::test::Options::get().ipcPath.string(); if (ipcPath.empty()) BOOST_FAIL("ERROR: ipcPath not set! (use --ipcpath or the environment variable ETH_TEST_IPC)"); diff --git a/test/Options.cpp b/test/Options.cpp index 1c46f8cf8..62269dcaa 100644 --- a/test/Options.cpp +++ b/test/Options.cpp @@ -35,12 +35,14 @@ using namespace dev::test; namespace fs = boost::filesystem; namespace po = boost::program_options; + Options const& Options::get() { static Options instance; return instance; } + Options::Options() { auto const& suite = boost::unit_test::framework::master_test_suite(); @@ -48,51 +50,13 @@ Options::Options() if (suite.argc == 0) return; - po::options_description options("", - po::options_description::m_default_line_length, - po::options_description::m_default_line_length - 23); - options.add_options() - ("testpath", po::value(&testPath)->default_value(getTestPath()), "path to test files") - ("ipcpath", po::value(&ipcPath)->default_value(getenv("ETH_TEST_IPC")), "path to ipc socket") - ("no-ipc", po::bool_switch(&disableIPC), "disable semantic tests") - ("no-smt", po::bool_switch(&disableSMT), "disable SMT checker") ("optimize", po::bool_switch(&optimize), "enables optimization") ("abiencoderv2", po::bool_switch(&useABIEncoderV2), "enables abi encoder v2") ("evm-version", po::value(&evmVersionString), "which evm version to use") ("show-messages", po::bool_switch(&showMessages), "enables message output"); - po::variables_map arguments; - - po::command_line_parser cmdLineParser(suite.argc, suite.argv); - cmdLineParser.options(options); - po::store(cmdLineParser.run(), arguments); - po::notify(arguments); - - if (!disableIPC) - { - solAssert( - !ipcPath.empty(), - "No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used." - ); - solAssert( - fs::exists(ipcPath), - "Invalid ipc path specified." - ); - } -} - -void Options::validate() const -{ - solAssert( - !dev::test::Options::get().testPath.empty(), - "No test path specified. The --testpath argument is required." - ); - if (!disableIPC) - solAssert( - !dev::test::Options::get().ipcPath.empty(), - "No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used." - ); + parse(suite.argc, suite.argv); } dev::solidity::EVMVersion Options::evmVersion() const diff --git a/test/Options.h b/test/Options.h index f510aade0..6e1395da8 100644 --- a/test/Options.h +++ b/test/Options.h @@ -14,17 +14,16 @@ You should have received a copy of the GNU General Public License along with solidity. If not, see . */ -/** @file TestHelper.h - */ #pragma once #include +#include #include #include +#include #include -#include #include @@ -33,17 +32,11 @@ namespace dev namespace test { -struct Options: boost::noncopyable +struct Options: CommonOptions { - std::string ipcPath; - boost::filesystem::path testPath; bool showMessages = false; - bool optimize = false; - bool disableIPC = false; - bool disableSMT = false; bool useABIEncoderV2 = false; - void validate() const; solidity::EVMVersion evmVersion() const; static Options const& get(); diff --git a/test/boostTest.cpp b/test/boostTest.cpp index 5cda2fae4..34412cb30 100644 --- a/test/boostTest.cpp +++ b/test/boostTest.cpp @@ -144,7 +144,7 @@ test_suite* init_unit_test_suite( int /*argc*/, char* /*argv*/[] ) master, options.testPath / ts.path, ts.subpath, - options.ipcPath, + options.ipcPath.string(), ts.testCaseCreator ) > 0, std::string("no ") + ts.title + " tests found"); } diff --git a/test/tools/CMakeLists.txt b/test/tools/CMakeLists.txt index 8200806d7..22730b103 100644 --- a/test/tools/CMakeLists.txt +++ b/test/tools/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(yulopti PRIVATE solidity ${Boost_PROGRAM_OPTIONS_LIBRARIES add_executable(isoltest isoltest.cpp + IsolTestOptions.cpp ../Options.cpp ../Common.cpp ../TestCase.cpp diff --git a/test/tools/IsolTestOptions.cpp b/test/tools/IsolTestOptions.cpp new file mode 100644 index 000000000..939910136 --- /dev/null +++ b/test/tools/IsolTestOptions.cpp @@ -0,0 +1,74 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** @file IsolTestOptions.cpp +* @date 2019 +*/ + +#include +#include +#include +#include + +namespace fs = boost::filesystem; +namespace po = boost::program_options; + +namespace dev +{ +namespace test +{ + +auto const description = R"(isoltest, tool for interactively managing test contracts. +Usage: isoltest [Options] --ipcpath ipcpath +Interactively validates test contracts. + +Allowed options)"; + +std::string editorPath() +{ + if (getenv("EDITOR")) + return getenv("EDITOR"); + else if (fs::exists("/usr/bin/editor")) + return "/usr/bin/editor"; + + return std::string{}; +} + +IsolTestOptions::IsolTestOptions(std::string* _editor): + CommonOptions(description) +{ + options.add_options() + ("help", po::bool_switch(&showHelp), "Show this help screen.") + ("no-color", po::bool_switch(&formatted), "don't use colors") + ("editor", po::value(_editor)->default_value(editorPath()), "editor for opening test files"); + +} + +bool IsolTestOptions::parse(int _argc, char const* const* _argv) +{ + bool const res = CommonOptions::parse(_argc, _argv); + + if (showHelp || !res) + { + std::cout << options << std::endl; + return false; + } + + return res; +} + +} +} diff --git a/test/tools/IsolTestOptions.h b/test/tools/IsolTestOptions.h new file mode 100644 index 000000000..58bc24e2e --- /dev/null +++ b/test/tools/IsolTestOptions.h @@ -0,0 +1,38 @@ +/* + This file is part of solidity. + + solidity is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + solidity is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with solidity. If not, see . +*/ +/** @file IsolTestOptions.h + */ + +#pragma once + +#include + +namespace dev +{ +namespace test +{ + +struct IsolTestOptions: CommonOptions +{ + bool formatted = true; + bool showHelp = false; + + IsolTestOptions(std::string* _editor); + bool parse(int _argc, char const* const* _argv) override; +}; +} +} diff --git a/test/tools/isoltest.cpp b/test/tools/isoltest.cpp index ceeef2906..66d8eba7e 100644 --- a/test/tools/isoltest.cpp +++ b/test/tools/isoltest.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -322,74 +323,18 @@ boost::optional runTestSuite( } -int main(int argc, char *argv[]) +int main(int argc, char const *argv[]) { setupTerminal(); - if (getenv("EDITOR")) - TestTool::editor = getenv("EDITOR"); - else if (fs::exists("/usr/bin/editor")) - TestTool::editor = "/usr/bin/editor"; + dev::test::IsolTestOptions options(&TestTool::editor); - fs::path testPath; - string ipcPath; - bool disableIPC = false; - bool disableSMT = false; - bool formatted = true; - - po::options_description options( - R"(isoltest, tool for interactively managing test contracts. -Usage: isoltest [Options] --ipcpath ipcpath -Interactively validates test contracts. - -Allowed options)", - po::options_description::m_default_line_length, - po::options_description::m_default_line_length - 23); - - options.add_options() - ("help", "Show this help screen.") - ("testpath", po::value(&testPath), "path to test files") - ("ipcpath", po::value(&ipcPath), "path to ipc socket") - ("no-ipc", "disable semantic tests") - ("no-smt", "disable SMT checker") - ("no-color", "don't use colors") - ("editor", po::value(&TestTool::editor), "editor for opening contracts"); - - po::variables_map arguments; try { - po::command_line_parser cmdLineParser(argc, argv); - cmdLineParser.options(options); - po::store(cmdLineParser.run(), arguments); - - if (arguments.count("help")) - { - cout << options << endl; - return 0; - } - - if (arguments.count("no-color")) - formatted = false; - - po::notify(arguments); - - if (arguments.count("no-ipc")) - disableIPC = true; + if (options.parse(argc, argv)) + options.validate(); else - { - solAssert( - !ipcPath.empty(), - "No ipc path specified. The --ipcpath argument is required, unless --no-ipc is used." - ); - solAssert( - fs::exists(ipcPath), - "Invalid ipc path specified." - ); - } - - if (arguments.count("no-smt")) - disableSMT = true; - + return 1; } catch (std::exception const& _exception) { @@ -397,29 +342,26 @@ Allowed options)", return 1; } - if (testPath.empty()) - testPath = dev::test::getTestPath(); - TestStats global_stats{0, 0}; // Actually run the tests. // Interactive tests are added in InteractiveTests.h for (auto const& ts: g_interactiveTestsuites) { - if (ts.ipc && disableIPC) + if (ts.ipc && options.disableIPC) continue; - if (ts.smt && disableSMT) + if (ts.smt && options.disableSMT) continue; - if (auto stats = runTestSuite(ts.title, testPath / ts.path, ts.subpath, ipcPath, ts.testCaseCreator, formatted)) + if (auto stats = runTestSuite(ts.title, options.testPath / ts.path, ts.subpath, options.ipcPath.string(), ts.testCaseCreator, options.formatted)) global_stats += *stats; else return 1; } cout << endl << "Summary: "; - AnsiColorized(cout, formatted, {BOLD, global_stats ? GREEN : RED}) << + AnsiColorized(cout, options.formatted, {BOLD, global_stats ? GREEN : RED}) << global_stats.successCount << "/" << global_stats.testCount; cout << " tests successful." << endl;