Skip to content
This repository has been archived by the owner on Oct 28, 2021. It is now read-only.

Commit

Permalink
testeth print test suite suggestions
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed May 4, 2019
1 parent e80e197 commit f85330e
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 0 deletions.
26 changes: 26 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ list(REMOVE_ITEM sources ${unittest_sources})
# search for test names and create ctest tests
set(excludeSuites jsonrpc \"customTestSuite\" BlockQueueSuite)
set(allSuites jsonrpc)
set(allTestsPart1 "")
set(allTestsPart2 "")
set(allTestsPart3 "")
set(allTestsPart4 "")
set(allTestsPart5 "")
foreach(file ${sources})
file(STRINGS ${file} test_list_raw REGEX "BOOST_.*TEST_(SUITE|CASE|SUITE_END)")
set(TestSuite "DEFAULT")
Expand Down Expand Up @@ -92,6 +97,23 @@ foreach(file ${sources})
set(TestEthArgs -t ${TestSuitePathFixed}/${TestCase} -- ${TESTETH_ARGS})
add_test(NAME ${TestSuitePathFixed}/${TestCase} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth ${TestEthArgs})
set_tests_properties(${TestSuitePathFixed}/${TestCase} PROPERTIES TIMEOUT ${timeout})

list(LENGTH allTestsPart1 allTestsPart1Length)
list(LENGTH allTestsPart2 allTestsPart2Length)
list(LENGTH allTestsPart3 allTestsPart3Length)
list(LENGTH allTestsPart4 allTestsPart4Length)
list(LENGTH allTestsPart5 allTestsPart5Length)
if(allTestsPart1Length LESS 100)
list(APPEND allTestsPart1 "${TestSuitePathFixed}/${TestCase} ")
elseif(allTestsPart2Length LESS 100)
list(APPEND allTestsPart2 "${TestSuitePathFixed}/${TestCase} ")
elseif(allTestsPart3Length LESS 100)
list(APPEND allTestsPart3 "${TestSuitePathFixed}/${TestCase} ")
elseif(allTestsPart4Length LESS 100)
list(APPEND allTestsPart4 "${TestSuitePathFixed}/${TestCase} ")
elseif(allTestsPart5Length LESS 100)
list(APPEND allTestsPart5 "${TestSuitePathFixed}/${TestCase} ")
endif()
endif()
endif()
elseif (";${test_raw};" MATCHES "BOOST_AUTO_TEST_SUITE_END()")
Expand All @@ -102,10 +124,14 @@ foreach(file ${sources})
endforeach(test_raw)
endforeach(file)

#Save allTests into a variable in include file
configure_file(tools/libtesteth/boostTest.h.in tools/libtesteth/boostTest.h)

hunter_add_package(yaml-cpp)
find_package(yaml-cpp CONFIG REQUIRED)

add_executable(testeth ${sources})
target_include_directories(testeth PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(testeth PRIVATE ${UTILS_INCLUDE_DIR})
target_link_libraries(testeth PRIVATE ethereum ethashseal web3jsonrpc devcrypto devcore aleth-buildinfo cryptopp-static yaml-cpp::yaml-cpp binaryen::binaryen libjson-rpc-cpp::client)
install(TARGETS testeth DESTINATION ${CMAKE_INSTALL_BINDIR})
Expand Down
30 changes: 30 additions & 0 deletions test/tools/libtesteth/TestHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,36 @@ string prepareLLLCVersionString()
return "Error getting LLLC Version";
}

// A simple C++ implementation of the Levenshtein distance algorithm to measure the amount of
// difference between two strings. https://gist.github.com/TheRayTracer/2644387
size_t levenshtein_distance(const char* s, size_t n, const char* t, size_t m)
{
++n;
++m;
size_t* d = new size_t[n * m];

memset(d, 0, sizeof(size_t) * n * m);
for (size_t i = 1, im = 0; i < m; ++i, ++im)
{
for (size_t j = 1, jn = 0; j < n; ++j, ++jn)
{
if (s[jn] == t[im])
d[(i * n) + j] = d[((i - 1) * n) + (j - 1)];
else
{
d[(i * n) + j] = min(d[(i - 1) * n + j] + 1, /* A deletion. */
min(d[i * n + (j - 1)] + 1, /* An insertion. */
d[(i - 1) * n + (j - 1)] + 1)); /* A substitution. */
}
}
}

size_t r = d[n * m - 1];
delete[] d;
return r;
}


void copyFile(fs::path const& _source, fs::path const& _destination)
{
fs::ifstream src(_source, ios::binary);
Expand Down
1 change: 1 addition & 0 deletions test/tools/libtesteth/TestHelper.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ bytes importByteArray(std::string const& _str);
void requireJsonFields(json_spirit::mObject const& _o, std::string const& _section,
std::map<std::string, json_spirit::Value_type> const& _validationMap);
void checkHexHasEvenLength(std::string const&);
size_t levenshtein_distance(const char* s, size_t n, const char* t, size_t m);
void copyFile(boost::filesystem::path const& _source, boost::filesystem::path const& _destination);
eth::LogEntries importLog(json_spirit::mArray const& _o);
std::string exportLog(eth::LogEntries const& _logs);
Expand Down
55 changes: 55 additions & 0 deletions test/tools/libtesteth/boostTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
#include <test/tools/jsontests/TransactionTests.h>
#include <test/tools/jsontests/vm.h>
#include <test/tools/libtesteth/TestHelper.h>
#include <test/tools/libtesteth/boostTest.h>
#include <boost/test/included/unit_test.hpp>
#include <boost/tokenizer.hpp>
#include <clocale>
#include <cstdlib>
#include <iostream>
Expand Down Expand Up @@ -82,9 +84,19 @@ int main(int argc, const char* argv[])
setDefaultOrCLocale();

// Initialize options
string sMinusTArg;
try
{
dev::test::Options::get(argc, argv);
for (int i = 0; i < argc; i++) // find -t boost arg
{
std::string arg = std::string{argv[i]};
if (arg == "-t" && i + 1 < argc)
{
sMinusTArg = std::string{argv[i + 1]};
break;
}
}
}
catch (dev::test::InvalidOption const& e)
{
Expand Down Expand Up @@ -137,6 +149,49 @@ int main(int argc, const char* argv[])
int result = 0;
auto fakeInit = [](int, char* []) -> boost::unit_test::test_suite* { return nullptr; };
result = unit_test_main(fakeInit, argc, const_cast<char**>(argv));

// Print suggestions of a test case
if (result == 200) // test suite not found
{
vector<string> availableTests;
typedef boost::char_separator<char> BoostSeparator;
BoostSeparator sep(";");
boost::tokenizer<BoostSeparator> tok(
boost_all_unit_tests_part1 + ";" + boost_all_unit_tests_part2 + ";" +
boost_all_unit_tests_part3 + ";" + boost_all_unit_tests_part4 + ";" +
boost_all_unit_tests_part5,
sep);
for (boost::tokenizer<BoostSeparator>::iterator it = tok.begin(); it != tok.end(); ++it)
availableTests.push_back(*it);

typedef std::pair<string, size_t> NameDistance;
std::vector<NameDistance> distanceMap; // <index in availableTests, compared distance>
for (auto& it : availableTests)
{
int dist = test::levenshtein_distance(
sMinusTArg.c_str(), sMinusTArg.size(), it.c_str(), it.size());
distanceMap.push_back({it, dist});
}
std::sort(distanceMap.begin(), distanceMap.end(),
[](NameDistance const& a, NameDistance const& b) { return a.second < b.second; });
std::cerr << "Did you mean: "
<< "\n";
std::set<string> suggestionSet;
size_t hasSlash = sMinusTArg.find_first_of("/");
for (size_t i = 0; i < 3; i++)
{
if (i < distanceMap.size())
{
string name = distanceMap[i].first;
if (hasSlash ==
string::npos) // if user input only test suite. print test suite suggestions
name = name.substr(0, name.find_first_of("/"));
suggestionSet.emplace(name);
}
}
for (auto const& it : suggestionSet)
std::cerr << "-t " << it << "\n";
}
dev::test::TestOutputHelper::get().printTestExecStats();
return result;
}
8 changes: 8 additions & 0 deletions test/tools/libtesteth/boostTest.h.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once
#include <string>

std::string boost_all_unit_tests_part1 = "@allTestsPart1@";
std::string boost_all_unit_tests_part2 = "@allTestsPart2@";
std::string boost_all_unit_tests_part3 = "@allTestsPart3@";
std::string boost_all_unit_tests_part4 = "@allTestsPart4@";
std::string boost_all_unit_tests_part5 = "@allTestsPart5@";

0 comments on commit f85330e

Please sign in to comment.