From 3660c4433695436b26118d78aee750952e1bf2fb Mon Sep 17 00:00:00 2001 From: Dimitry Date: Wed, 3 Jun 2015 17:21:29 +0300 Subject: [PATCH] FuzzTests: Boost Macro --- test/TestHelper.h | 16 +++ test/fuzzTesting/CMakeLists.txt | 5 + test/fuzzTesting/createRandomTest.cpp | 143 ++++++++++++++++++++++++++ test/libethereum/transaction.cpp | 43 ++++---- 4 files changed, 186 insertions(+), 21 deletions(-) create mode 100644 test/fuzzTesting/createRandomTest.cpp diff --git a/test/TestHelper.h b/test/TestHelper.h index 8f0c73bf3..eaeed619a 100644 --- a/test/TestHelper.h +++ b/test/TestHelper.h @@ -31,6 +31,19 @@ #include #include +#define DONTUSE_BOOST_MACROS +#ifdef DONTUSE_BOOST_MACROS + #define TBOOST_THROW_EXCEPTION(arg) throw; + #define TBOOST_REQUIRE(arg) if(arg == false) throw; + #define TBOOST_CHECK_MESSAGE(arg1, arg2) if(arg1 == false) throw; + #define TBOOST_WARN_MESSAGE(arg1, arg2) throw; +#else + #define TBOOST_THROW_EXCEPTION(arg) BOOST_THROW_EXCEPTION(arg) + #define TBOOST_REQUIRE(arg) BOOST_REQUIRE(arg) + #define TBOOST_CHECK_MESSAGE(arg1, arg2) BOOST_CHECK_MESSAGE(arg1, arg2) + #define TBOOST_WARN_MESSAGE(arg1, arg2) BOOST_WARN_MESSAGE(arg1, arg2) +#endif + namespace dev { namespace eth @@ -163,6 +176,9 @@ eth::LastHashes lastHashes(u256 _currentBlockNumber); json_spirit::mObject fillJsonWithState(eth::State _state); json_spirit::mObject fillJsonWithTransaction(eth::Transaction _txn); +//Fill Test Functions +void doTransactionTests(json_spirit::mValue& _v, bool _fillin); + template void checkAddresses(mapType& _expectedAddrs, mapType& _resultAddrs) { diff --git a/test/fuzzTesting/CMakeLists.txt b/test/fuzzTesting/CMakeLists.txt index 371d6504d..4024b7956 100644 --- a/test/fuzzTesting/CMakeLists.txt +++ b/test/fuzzTesting/CMakeLists.txt @@ -8,6 +8,7 @@ include_directories(${Boost_INCLUDE_DIRS}) include_directories(${CRYPTOPP_INCLUDE_DIRS}) include_directories(${JSON_RPC_CPP_INCLUDE_DIRS}) +add_executable(createRandomTest "./createRandomTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp" "../libethereum/transaction.cpp") add_executable(createRandomVMTest "./createRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp") add_executable(createRandomStateTest "./createRandomStateTest.cpp" "../TestHelper.cpp" "../Stats.cpp" "fuzzHelper.cpp") add_executable(checkRandomVMTest "./checkRandomVMTest.cpp" "../libevm/vm.cpp" "../TestHelper.cpp" "../Stats.cpp" ) @@ -32,3 +33,7 @@ target_link_libraries(checkRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES target_link_libraries(checkRandomStateTest ethereum) target_link_libraries(checkRandomStateTest ethcore) target_link_libraries(checkRandomStateTest testutils) +target_link_libraries(createRandomTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(createRandomTest ethereum) +target_link_libraries(createRandomTest ethcore) +target_link_libraries(createRandomTest testutils) diff --git a/test/fuzzTesting/createRandomTest.cpp b/test/fuzzTesting/createRandomTest.cpp new file mode 100644 index 000000000..92fd21b76 --- /dev/null +++ b/test/fuzzTesting/createRandomTest.cpp @@ -0,0 +1,143 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum 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. + + cpp-ethereum 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 cpp-ethereum. If not, see . +*/ +/** @file createRandomTest.cpp + * @author Dimitry Khokhlov + * @date 2015 + */ + +#include +#include + +#include +#include + + +extern std::string const c_testExampleTransactionTest; +std::vector getTypes(); +void parseTestWithTypes(std::string& test); +void randomTransactionTest(); +void randomBlockChainTest(); + +int main(int argc, char *argv[]) +{ + std::string testSuite; + for (auto i = 0; i < argc; ++i) + { + auto arg = std::string{argv[i]}; + dev::test::Options& options = const_cast(dev::test::Options::get()); + if (arg == "--fulloutput") + options.fulloutput = true; + if (arg == "-t" && i + 1 < argc) + { + testSuite = argv[i + 1]; + if (testSuite != "BlockChainTests" && testSuite != "TransactionTests") + testSuite = ""; + } + } + + if (testSuite == "") + std::cout << "Error! Test suite not supported! (Usage -t TestSuite)"; + else + if (testSuite == "BlockChainTests") + randomBlockChainTest(); + else + if (testSuite == "TransactionTests") + randomTransactionTest(); + + return 0; +} + +void randomTransactionTest() +{ + std::string newTest = c_testExampleTransactionTest; + parseTestWithTypes(newTest); + json_spirit::mValue v; + json_spirit::read_string(newTest, v); + dev::test::doTransactionTests(v, true); + std::cout << json_spirit::write_string(v, true); +} + +void randomBlockChainTest() +{ + +} + +/// Parse Test string replacing keywords to fuzzed values +void parseTestWithTypes(std::string& test) +{ + std::vector types = getTypes(); + for (unsigned i = 0; i < types.size(); i++) + { + std::size_t pos = test.find(types.at(i)); + while (pos != std::string::npos) + { + if (types.at(i) == "[CODE]") + test.replace(pos, 6, "0x"+dev::test::RandomCode::generate(10)); + else + if (types.at(i) == "[HEX]") + test.replace(pos, 5, dev::test::RandomCode::randomUniIntHex()); + else + if (types.at(i) == "[HASH20]") + test.replace(pos, 8, dev::test::RandomCode::rndByteSequence(20)); + else + if (types.at(i) == "[0xHASH32]") + test.replace(pos, 10, "0x" + dev::test::RandomCode::rndByteSequence(32)); + else + if (types.at(i) == "[V]") + { + int random = dev::test::RandomCode::randomUniInt() % 100; + if (random < 30) + test.replace(pos, 3, "28"); + else + if (random < 60) + test.replace(pos, 3, "29"); + else + test.replace(pos, 3, "0x" + dev::test::RandomCode::rndByteSequence(1)); + } + + pos = test.find(types.at(i)); + } + } +} + +std::vector getTypes() +{ + return {"[CODE]", "[HEX]", "[HASH20]", "[0xHASH32]", "[V]"}; +} + + +std::string const c_testExampleTransactionTest = R"( +{ +"TransactionTest" : { + "transaction" : + { + "data" : "[CODE]", + "gasLimit" : "[HEX]", + "gasPrice" : "[HEX]", + "nonce" : "[HEX]", + "to" : "[HASH20]", + "value" : "[HEX]", + "v" : "[V]", + "r" : "[0xHASH32]", + "s" : "[0xHASH32]" + } + } +} +)"; + + + diff --git a/test/libethereum/transaction.cpp b/test/libethereum/transaction.cpp index 017e51ded..ad20331b3 100644 --- a/test/libethereum/transaction.cpp +++ b/test/libethereum/transaction.cpp @@ -21,6 +21,7 @@ */ #include "../TestHelper.h" +#include "test/fuzzTesting/fuzzHelper.h" using namespace std; using namespace json_spirit; @@ -38,7 +39,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) if (_fillin) { - BOOST_REQUIRE(o.count("transaction") > 0); + TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); //Construct Rlp of the given transaction @@ -49,7 +50,7 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { Transaction txFromFields(rlpStream.out(), CheckTransaction::Everything); if (!txFromFields.signature().isValid()) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); o["sender"] = toString(txFromFields.sender()); o["transaction"] = ImportTest::makeAllFieldsHex(tObj); @@ -63,9 +64,9 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectInValid = (o["expect"].get_str() == "invalid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); + {TBOOST_CHECK_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} else - BOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!"); + {TBOOST_WARN_MESSAGE(expectInValid, "Check state: Transaction '" << i.first << "' is expected to be valid!");} o.erase(o.find("expect")); } @@ -76,16 +77,16 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) { bool expectValid = (o["expect"].get_str() == "valid"); if (Options::get().checkState) - BOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); + {TBOOST_CHECK_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} else - BOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!"); + {TBOOST_WARN_MESSAGE(expectValid, "Check state: Transaction '" << i.first << "' is expected to be invalid!");} o.erase(o.find("expect")); } } else { - BOOST_REQUIRE(o.count("rlp") > 0); + TBOOST_REQUIRE((o.count("rlp") > 0)); Transaction txFromRlp; try { @@ -93,39 +94,39 @@ void doTransactionTests(json_spirit::mValue& _v, bool _fillin) RLP rlp(stream); txFromRlp = Transaction(rlp.data(), CheckTransaction::Everything); if (!txFromRlp.signature().isValid()) - BOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); + TBOOST_THROW_EXCEPTION(Exception() << errinfo_comment("transaction from RLP signature is invalid") ); } catch(Exception const& _e) { cnote << i.first; cnote << "Transaction Exception: " << diagnostic_information(_e); - BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); + TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } catch(...) { - BOOST_CHECK_MESSAGE(o.count("transaction") == 0, "A transaction object should not be defined because the RLP is invalid!"); + TBOOST_CHECK_MESSAGE((o.count("transaction") == 0), "A transaction object should not be defined because the RLP is invalid!"); continue; } - BOOST_REQUIRE(o.count("transaction") > 0); + TBOOST_REQUIRE((o.count("transaction") > 0)); mObject tObj = o["transaction"].get_obj(); Transaction txFromFields(createRLPStreamFromTransactionFields(tObj).out(), CheckTransaction::Everything); //Check the fields restored from RLP to original fields - BOOST_CHECK_MESSAGE(txFromFields.data() == txFromRlp.data(), "Data in given RLP not matching the Transaction data!"); - BOOST_CHECK_MESSAGE(txFromFields.value() == txFromRlp.value(), "Value in given RLP not matching the Transaction value!"); - BOOST_CHECK_MESSAGE(txFromFields.gasPrice() == txFromRlp.gasPrice(), "GasPrice in given RLP not matching the Transaction gasPrice!"); - BOOST_CHECK_MESSAGE(txFromFields.gas() == txFromRlp.gas(),"Gas in given RLP not matching the Transaction gas!"); - BOOST_CHECK_MESSAGE(txFromFields.nonce() == txFromRlp.nonce(),"Nonce in given RLP not matching the Transaction nonce!"); - BOOST_CHECK_MESSAGE(txFromFields.receiveAddress() == txFromRlp.receiveAddress(), "Receive address in given RLP not matching the Transaction 'to' address!"); - BOOST_CHECK_MESSAGE(txFromFields.sender() == txFromRlp.sender(), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); - BOOST_CHECK_MESSAGE(txFromFields == txFromRlp, "However, txFromFields != txFromRlp!"); - BOOST_REQUIRE (o.count("sender") > 0); + TBOOST_CHECK_MESSAGE((txFromFields.data() == txFromRlp.data()), "Data in given RLP not matching the Transaction data!"); + TBOOST_CHECK_MESSAGE((txFromFields.value() == txFromRlp.value()), "Value in given RLP not matching the Transaction value!"); + TBOOST_CHECK_MESSAGE((txFromFields.gasPrice() == txFromRlp.gasPrice()), "GasPrice in given RLP not matching the Transaction gasPrice!"); + TBOOST_CHECK_MESSAGE((txFromFields.gas() == txFromRlp.gas()),"Gas in given RLP not matching the Transaction gas!"); + TBOOST_CHECK_MESSAGE((txFromFields.nonce() == txFromRlp.nonce()),"Nonce in given RLP not matching the Transaction nonce!"); + TBOOST_CHECK_MESSAGE((txFromFields.receiveAddress() == txFromRlp.receiveAddress()), "Receive address in given RLP not matching the Transaction 'to' address!"); + TBOOST_CHECK_MESSAGE((txFromFields.sender() == txFromRlp.sender()), "Transaction sender address in given RLP not matching the Transaction 'vrs' signature!"); + TBOOST_CHECK_MESSAGE((txFromFields == txFromRlp), "However, txFromFields != txFromRlp!"); + TBOOST_REQUIRE ((o.count("sender") > 0)); Address addressReaded = Address(o["sender"].get_str()); - BOOST_CHECK_MESSAGE(txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded, "Signature address of sender does not match given sender address!"); + TBOOST_CHECK_MESSAGE((txFromFields.sender() == addressReaded || txFromRlp.sender() == addressReaded), "Signature address of sender does not match given sender address!"); } }//for }//doTransactionTests