Browse Source

Merge branch 'p2p' into reqpeer

cl-refactor
subtly 10 years ago
parent
commit
2046ce2b1d
  1. 3
      CMakeLists.txt
  2. 66
      abi/main.cpp
  3. 2
      libethereum/Client.h
  4. 5
      libethereum/ClientBase.cpp
  5. 2
      libethereum/ClientBase.h
  6. 1
      libtestutils/FixedClient.h
  7. 6
      mix/qml/html/cm/codemirror.css
  8. 118
      mix/qml/html/cm/mark-selection.js
  9. 3
      mix/qml/html/cm/solarized.css
  10. 1
      mix/qml/html/codeeditor.html
  11. 3
      mix/qml/html/codeeditor.js
  12. 1
      mix/web.qrc
  13. 39
      test/CMakeLists.txt
  14. 202
      test/ClientBase.cpp
  15. 16
      test/TestHelper.cpp
  16. 2
      test/TestHelper.h
  17. 117
      test/TestUtils.cpp
  18. 82
      test/TestUtils.h

3
CMakeLists.txt

@ -229,9 +229,6 @@ if (NOT JUSTTESTS)
endif()
enable_testing()
add_test(NAME alltests WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth)
#unset(TARGET_PLATFORM CACHE)
if (WIN32)

66
abi/main.cpp

@ -202,6 +202,20 @@ struct ABIType
return ret;
}
bool isBytes() const { return base == Base::Bytes && !size; }
string render(bytes const& _data) const
{
if (base == Base::Uint)
return toString(fromBigEndian<u256>(_data));
else if (base == Base::Int)
return toString((s256)fromBigEndian<u256>(_data));
else if (base == Base::Address)
return toString(Address(h256(_data)));
else
return toHex(_data);
}
void noteHexInput(unsigned _nibbles) { if (base == Base::Unknown) { if (_nibbles == 40) base = Base::Address; else { base = Base::Bytes; size = _nibbles / 2; } } }
void noteBinaryInput() { if (base == Base::Unknown) { base = Base::Bytes; size = 32; } }
void noteDecimalInput() { if (base == Base::Unknown) { base = Base::Uint; size = 32; } }
@ -341,6 +355,9 @@ struct ABIMethod
bytes encode(vector<pair<bytes, Format>> const& _params) const
{
// ALL WRONG!!!!
// INARITIES SHOULD BE HEIRARCHICAL!
bytes ret = name.empty() ? bytes() : id().asBytes();
unsigned pi = 0;
vector<unsigned> inArity;
@ -356,6 +373,9 @@ struct ABIMethod
}
else
arity *= j;
if (i.isBytes())
for (unsigned i = 0; i < arity; ++i)
inArity.push_back(arity);
}
unsigned ii = 0;
@ -382,6 +402,52 @@ struct ABIMethod
stringstream out;
if (_index == -1)
out << "[";
unsigned di = 0;
vector<ABIType> souts;
vector<unsigned> catDims;
for (ABIType a: outs)
{
unsigned q = 1;
for (auto& i: a.dims)
{
for (unsigned j = 0; j < q; ++j)
if (i == -1)
{
catDims.push_back(fromBigEndian<unsigned>(bytesConstRef(&_data).cropped(di, 32)));
di += 32;
}
q *= i;
}
if (a.isBytes())
souts.push_back(a);
}
for (ABIType const& a: souts)
{
auto put = [&]() {
out << a.render(bytesConstRef(&_data).cropped(di, 32).toBytes()) << ", ";
di += 32;
};
function<void(vector<int>)> putDim = [&](vector<int> addr) {
if (addr.size() == a.dims.size())
put();
else
{
out << "[";
auto d = addr;
addr.push_back(0);
for (addr.back() = 0; addr.back() < a.dims[addr.size() - 1]; ++addr.back())
{
if (addr.back())
out << ", ";
putDim(addr);
}
out << "]";
}
};
putDim(vector<int>());
if (_index == -1)
out << ", ";
}
(void)_data;
if (_index == -1)
out << "]";

2
libethereum/Client.h

@ -171,6 +171,8 @@ public:
// Mining stuff:
void setAddress(Address _us) { WriteGuard l(x_stateDB); m_preMine.setAddress(_us); }
/// Check block validity prior to mining.
bool miningParanoia() const { return m_paranoia; }
/// Change whether we check block validity prior to mining.

5
libethereum/ClientBase.cpp

@ -393,11 +393,6 @@ u256 ClientBase::gasLimitRemaining() const
return postMine().gasLimitRemaining();
}
void ClientBase::setAddress(Address _us)
{
preMine().setAddress(_us);
}
Address ClientBase::address() const
{
return preMine().address();

2
libethereum/ClientBase.h

@ -131,7 +131,7 @@ public:
virtual u256 gasLimitRemaining() const override;
/// Set the coinbase address
virtual void setAddress(Address _us) override;
virtual void setAddress(Address _us) = 0;
/// Get the coinbase address
virtual Address address() const override;

1
libtestutils/FixedClient.h

@ -47,6 +47,7 @@ public:
virtual eth::State asOf(h256 const& _h) const override;
virtual eth::State preMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual eth::State postMine() const override { ReadGuard l(x_stateDB); return m_state; }
virtual void setAddress(Address _us) { WriteGuard l(x_stateDB); m_state.setAddress(_us); }
virtual void prepareForTransaction() override {}
private:

6
mix/qml/html/cm/codemirror.css

@ -304,12 +304,12 @@ div.CodeMirror-cursors {
@media print {
/* Hide the cursor when printing */
.CodeMirror div.CodeMirror-cursors {
visibility: hidden;
visibility: hidden;
}
}
/* See issue #2901 */
.cm-tab-wrap-hack:after { content: ''; }
/* Help users use markselection to safely style text background */
span.CodeMirror-selectedtext { background: none; }
/* Help users use markselection to safely style text background
span.CodeMirror-selectedtext { color: #586e75; } */

118
mix/qml/html/cm/mark-selection.js

@ -0,0 +1,118 @@
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Because sometimes you need to mark the selected *text*.
//
// Adds an option 'styleSelectedText' which, when enabled, gives
// selected text the CSS class given as option value, or
// "CodeMirror-selectedtext" when the value is not a string.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineOption("styleSelectedText", false, function(cm, val, old) {
var prev = old && old != CodeMirror.Init;
if (val && !prev) {
cm.state.markedSelection = [];
cm.state.markedSelectionStyle = typeof val == "string" ? val : "CodeMirror-selectedtext";
reset(cm);
cm.on("cursorActivity", onCursorActivity);
cm.on("change", onChange);
} else if (!val && prev) {
cm.off("cursorActivity", onCursorActivity);
cm.off("change", onChange);
clear(cm);
cm.state.markedSelection = cm.state.markedSelectionStyle = null;
}
});
function onCursorActivity(cm) {
cm.operation(function() { update(cm); });
}
function onChange(cm) {
if (cm.state.markedSelection.length)
cm.operation(function() { clear(cm); });
}
var CHUNK_SIZE = 8;
var Pos = CodeMirror.Pos;
var cmp = CodeMirror.cmpPos;
function coverRange(cm, from, to, addAt) {
if (cmp(from, to) == 0) return;
var array = cm.state.markedSelection;
var cls = cm.state.markedSelectionStyle;
for (var line = from.line;;) {
var start = line == from.line ? from : Pos(line, 0);
var endLine = line + CHUNK_SIZE, atEnd = endLine >= to.line;
var end = atEnd ? to : Pos(endLine, 0);
var mark = cm.markText(start, end, {className: cls});
if (addAt == null) array.push(mark);
else array.splice(addAt++, 0, mark);
if (atEnd) break;
line = endLine;
}
}
function clear(cm) {
var array = cm.state.markedSelection;
for (var i = 0; i < array.length; ++i) array[i].clear();
array.length = 0;
}
function reset(cm) {
clear(cm);
var ranges = cm.listSelections();
for (var i = 0; i < ranges.length; i++)
coverRange(cm, ranges[i].from(), ranges[i].to());
}
function update(cm) {
if (!cm.somethingSelected()) return clear(cm);
if (cm.listSelections().length > 1) return reset(cm);
var from = cm.getCursor("start"), to = cm.getCursor("end");
var array = cm.state.markedSelection;
if (!array.length) return coverRange(cm, from, to);
var coverStart = array[0].find(), coverEnd = array[array.length - 1].find();
if (!coverStart || !coverEnd || to.line - from.line < CHUNK_SIZE ||
cmp(from, coverEnd.to) >= 0 || cmp(to, coverStart.from) <= 0)
return reset(cm);
while (cmp(from, coverStart.from) > 0) {
array.shift().clear();
coverStart = array[0].find();
}
if (cmp(from, coverStart.from) < 0) {
if (coverStart.to.line - from.line < CHUNK_SIZE) {
array.shift().clear();
coverRange(cm, from, coverStart.to, 0);
} else {
coverRange(cm, from, coverStart.from, 0);
}
}
while (cmp(to, coverEnd.to) < 0) {
array.pop().clear();
coverEnd = array[array.length - 1].find();
}
if (cmp(to, coverEnd.to) > 0) {
if (to.line - coverEnd.from.line < CHUNK_SIZE) {
array.pop().clear();
coverRange(cm, coverEnd.from, to);
} else {
coverRange(cm, coverEnd.to, to);
}
}
}
});

3
mix/qml/html/cm/solarized.css

@ -166,7 +166,7 @@ view-port
/* Code execution */
.CodeMirror-exechighlight {
background: rgba(255, 255, 255, 0.10);
background: #eee8d5;
}
/* Error annotation */
@ -182,3 +182,4 @@ view-port
padding: 2px;
}
span.CodeMirror-selectedtext { color: #586e75 !important; }

1
mix/qml/html/codeeditor.html

@ -22,6 +22,7 @@
<script src="cm/javascript-hint.js"></script>
<script src="cm/anyword-hint.js"></script>
<script src="cm/closebrackets.js"></script>
<script src="cm/mark-selection.js"></script>
<script src="cm/errorannotation.js"></script>
<script src="cm/tern.js"></script>
<script src="cm/acorn.js"></script>

3
mix/qml/html/codeeditor.js

@ -4,7 +4,8 @@ var editor = CodeMirror(document.body, {
matchBrackets: true,
autofocus: true,
gutters: ["CodeMirror-linenumbers", "breakpoints"],
autoCloseBrackets: true
autoCloseBrackets: true,
styleSelectedText: true
});
var ternServer;

1
mix/web.qrc

@ -39,5 +39,6 @@
<file>qml/html/cm/acorn.js</file>
<file>qml/html/cm/acorn_loose.js</file>
<file>qml/html/cm/walk.js</file>
<file>qml/html/cm/mark-selection.js</file>
</qresource>
</RCC>

39
test/CMakeLists.txt

@ -16,6 +16,21 @@ include_directories(${Boost_INCLUDE_DIRS})
include_directories(${CRYPTOPP_INCLUDE_DIRS})
include_directories(${JSON_RPC_CPP_INCLUDE_DIRS})
# search for test names and create ctest tests
enable_testing()
foreach(file ${SRC_LIST})
file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/${file} test_list_raw REGEX "BOOST_.*TEST_(SUITE|CASE)")
set(TestSuite "DEFAULT")
foreach(test_raw ${test_list_raw})
string(REGEX REPLACE ".*TEST_(SUITE|CASE)\\(([^ ,\\)]*).*" "\\1 \\2" test ${test_raw})
if(test MATCHES "^SUITE .*")
string(SUBSTRING ${test} 6 -1 TestSuite)
elseif(test MATCHES "^CASE .*")
string(SUBSTRING ${test} 5 -1 TestCase)
add_test(NAME ${TestSuite}/${TestCase} WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/test COMMAND testeth -t ${TestSuite}/${TestCase})
endif(test MATCHES "^SUITE .*")
endforeach(test_raw)
endforeach(file)
file(GLOB HEADERS "*.h")
add_executable(testeth ${SRC_LIST} ${HEADERS})
@ -30,6 +45,7 @@ target_link_libraries(testeth ethereum)
target_link_libraries(testeth ethcore)
target_link_libraries(testeth secp256k1)
target_link_libraries(testeth solidity)
target_link_libraries(testeth testutils)
if (NOT HEADLESS AND NOT JUSTTESTS)
target_link_libraries(testeth webthree)
target_link_libraries(testeth natspec)
@ -42,13 +58,36 @@ endif()
target_link_libraries(createRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(createRandomVMTest ethereum)
target_link_libraries(createRandomVMTest ethcore)
target_link_libraries(createRandomVMTest testutils)
target_link_libraries(createRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(createRandomStateTest ethereum)
target_link_libraries(createRandomStateTest ethcore)
target_link_libraries(createRandomStateTest testutils)
target_link_libraries(checkRandomVMTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(checkRandomVMTest ethereum)
target_link_libraries(checkRandomVMTest ethcore)
target_link_libraries(checkRandomVMTest testutils)
target_link_libraries(checkRandomStateTest ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES})
target_link_libraries(checkRandomStateTest ethereum)
target_link_libraries(checkRandomStateTest ethcore)
target_link_libraries(checkRandomStateTest testutils)
enable_testing()
set(CTEST_OUTPUT_ON_FAILURE TRUE)
include(EthUtils)
eth_add_test(ClientBase
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=1
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=3
ARGS --eth_testfile=BlockTests/bcJS_API_Test --eth_threads=10
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=1
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=3
ARGS --eth_testfile=BlockTests/bcValidBlockTest --eth_threads=10
)
eth_add_test(JsonRpc
ARGS --eth_testfile=BlockTests/bcJS_API_Test
ARGS --eth_testfile=BlockTests/bcValidBlockTest
)

202
test/ClientBase.cpp

@ -0,0 +1,202 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file ClientBase.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <boost/test/unit_test.hpp>
#include <libdevcore/CommonJS.h>
#include "TestUtils.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
BOOST_FIXTURE_TEST_SUITE(ClientBase, ParallelClientBaseFixture)
BOOST_AUTO_TEST_CASE(blocks)
{
enumerateClients([](Json::Value const& _json, dev::eth::ClientBase& _client) -> void
{
for (string const& name: _json["postState"].getMemberNames())
{
Json::Value o = _json["postState"][name];
Address address(name);
// balanceAt
u256 expectedBalance = u256(o["balance"].asString());
u256 balance = _client.balanceAt(address);
ETH_CHECK_EQUAL(expectedBalance, balance);
// countAt
u256 expectedCount = u256(o["nonce"].asString());
u256 count = _client.countAt(address);
ETH_CHECK_EQUAL(expectedCount, count);
// stateAt
for (string const& pos: o["storage"].getMemberNames())
{
u256 expectedState = u256(o["storage"][pos].asString());
u256 state = _client.stateAt(address, u256(pos));
ETH_CHECK_EQUAL(expectedState, state);
}
// codeAt
bytes expectedCode = fromHex(o["code"].asString());
bytes code = _client.codeAt(address);
ETH_CHECK_EQUAL_COLLECTIONS(expectedCode.begin(), expectedCode.end(),
code.begin(), code.end());
}
// number
unsigned expectedNumber = _json["blocks"].size();
unsigned number = _client.number();
ETH_CHECK_EQUAL(expectedNumber, number);
u256 totalDifficulty = u256(_json["genesisBlockHeader"]["difficulty"].asString());
for (Json::Value const& block: _json["blocks"])
{
Json::Value blockHeader = block["blockHeader"];
Json::Value uncles = block["uncleHeaders"];
Json::Value transactions = block["transactions"];
h256 blockHash = h256(fromHex(blockHeader["hash"].asString()));
// just update the difficulty
for (Json::Value const& uncle: uncles)
{
totalDifficulty += u256(uncle["difficulty"].asString());
}
// hashFromNumber
h256 expectedHashFromNumber = h256(fromHex(blockHeader["hash"].asString()));
h256 hashFromNumber = _client.hashFromNumber(jsToInt(blockHeader["number"].asString()));
ETH_CHECK_EQUAL(expectedHashFromNumber, hashFromNumber);
// blockInfo
auto compareBlockInfos = [](Json::Value const& _b, BlockInfo _blockInfo) -> void
{
LogBloom expectedBlockInfoBloom = LogBloom(fromHex(_b["bloom"].asString()));
Address expectedBlockInfoCoinbase = Address(fromHex(_b["coinbase"].asString()));
u256 expectedBlockInfoDifficulty = u256(_b["difficulty"].asString());
bytes expectedBlockInfoExtraData = fromHex(_b["extraData"].asString());
u256 expectedBlockInfoGasLimit = u256(_b["gasLimit"].asString());
u256 expectedBlockInfoGasUsed = u256(_b["gasUsed"].asString());
h256 expectedBlockInfoHash = h256(fromHex(_b["hash"].asString()));
h256 expectedBlockInfoMixHash = h256(fromHex(_b["mixHash"].asString()));
Nonce expectedBlockInfoNonce = Nonce(fromHex(_b["nonce"].asString()));
u256 expectedBlockInfoNumber = u256(_b["number"].asString());
h256 expectedBlockInfoParentHash = h256(fromHex(_b["parentHash"].asString()));
h256 expectedBlockInfoReceiptsRoot = h256(fromHex(_b["receiptTrie"].asString()));
u256 expectedBlockInfoTimestamp = u256(_b["timestamp"].asString());
h256 expectedBlockInfoTransactionsRoot = h256(fromHex(_b["transactionsTrie"].asString()));
h256 expectedBlockInfoUncldeHash = h256(fromHex(_b["uncleHash"].asString()));
ETH_CHECK_EQUAL(expectedBlockInfoBloom, _blockInfo.logBloom);
ETH_CHECK_EQUAL(expectedBlockInfoCoinbase, _blockInfo.coinbaseAddress);
ETH_CHECK_EQUAL(expectedBlockInfoDifficulty, _blockInfo.difficulty);
ETH_CHECK_EQUAL_COLLECTIONS(expectedBlockInfoExtraData.begin(), expectedBlockInfoExtraData.end(),
_blockInfo.extraData.begin(), _blockInfo.extraData.end());
ETH_CHECK_EQUAL(expectedBlockInfoGasLimit, _blockInfo.gasLimit);
ETH_CHECK_EQUAL(expectedBlockInfoGasUsed, _blockInfo.gasUsed);
ETH_CHECK_EQUAL(expectedBlockInfoHash, _blockInfo.hash);
ETH_CHECK_EQUAL(expectedBlockInfoMixHash, _blockInfo.mixHash);
ETH_CHECK_EQUAL(expectedBlockInfoNonce, _blockInfo.nonce);
ETH_CHECK_EQUAL(expectedBlockInfoNumber, _blockInfo.number);
ETH_CHECK_EQUAL(expectedBlockInfoParentHash, _blockInfo.parentHash);
ETH_CHECK_EQUAL(expectedBlockInfoReceiptsRoot, _blockInfo.receiptsRoot);
ETH_CHECK_EQUAL(expectedBlockInfoTimestamp, _blockInfo.timestamp);
ETH_CHECK_EQUAL(expectedBlockInfoTransactionsRoot, _blockInfo.transactionsRoot);
ETH_CHECK_EQUAL(expectedBlockInfoUncldeHash, _blockInfo.sha3Uncles);
};
BlockInfo blockInfo = _client.blockInfo(blockHash);
compareBlockInfos(blockHeader, blockInfo);
// blockDetails
unsigned expectedBlockDetailsNumber = jsToInt(blockHeader["number"].asString());
totalDifficulty += u256(blockHeader["difficulty"].asString());
BlockDetails blockDetails = _client.blockDetails(blockHash);
ETH_CHECK_EQUAL(expectedBlockDetailsNumber, blockDetails.number);
ETH_CHECK_EQUAL(totalDifficulty, blockDetails.totalDifficulty);
auto compareTransactions = [](Json::Value const& _t, Transaction _transaction) -> void
{
bytes expectedTransactionData = fromHex(_t["data"].asString());
u256 expectedTransactionGasLimit = u256(_t["gasLimit"].asString());
u256 expectedTransactionGasPrice = u256(_t["gasPrice"].asString());
u256 expectedTransactionNonce = u256(_t["nonce"].asString());
u256 expectedTransactionSignatureR = h256(fromHex(_t["r"].asString()));
u256 expectedTransactionSignatureS = h256(fromHex(_t["s"].asString()));
// unsigned expectedTransactionSignatureV = jsToInt(t["v"].asString());
ETH_CHECK_EQUAL_COLLECTIONS(expectedTransactionData.begin(), expectedTransactionData.end(),
_transaction.data().begin(), _transaction.data().end());
ETH_CHECK_EQUAL(expectedTransactionGasLimit, _transaction.gas());
ETH_CHECK_EQUAL(expectedTransactionGasPrice, _transaction.gasPrice());
ETH_CHECK_EQUAL(expectedTransactionNonce, _transaction.nonce());
ETH_CHECK_EQUAL(expectedTransactionSignatureR, _transaction.signature().r);
ETH_CHECK_EQUAL(expectedTransactionSignatureS, _transaction.signature().s);
// ETH_CHECK_EQUAL(expectedTransactionSignatureV, _transaction.signature().v); // 27 === 0x0, 28 === 0x1, not sure why
};
Transactions ts = _client.transactions(blockHash);
TransactionHashes tHashes = _client.transactionHashes(blockHash);
unsigned tsCount = _client.transactionCount(blockHash);
ETH_REQUIRE(transactions.size() == ts.size());
ETH_REQUIRE(transactions.size() == tHashes.size());
// transactionCount
ETH_CHECK_EQUAL(transactions.size(), tsCount);
for (unsigned i = 0; i < tsCount; i++)
{
Json::Value t = transactions[i];
// transaction (by block hash and transaction index)
Transaction transaction = _client.transaction(blockHash, i);
compareTransactions(t, transaction);
// transaction (by hash)
Transaction transactionByHash = _client.transaction(transaction.sha3());
compareTransactions(t, transactionByHash);
// transactions
compareTransactions(t, ts[i]);
// transactionHashes
ETH_CHECK_EQUAL(transaction.sha3(), tHashes[i]);
}
// uncleCount
unsigned usCount = _client.uncleCount(blockHash);
ETH_CHECK_EQUAL(uncles.size(), usCount);
for (unsigned i = 0; i < usCount; i++)
{
Json::Value u = uncles[i];
// uncle (by hash)
BlockInfo uncle = _client.uncle(blockHash, i);
compareBlockInfos(u, uncle);
}
}
});
}
BOOST_AUTO_TEST_SUITE_END()

16
test/TestHelper.cpp

@ -374,22 +374,6 @@ void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _e
}
}
std::string getTestPath()
{
string testPath;
const char* ptestPath = getenv("ETHEREUM_TEST_PATH");
if (ptestPath == NULL)
{
cnote << " could not find environment variable ETHEREUM_TEST_PATH \n";
testPath = "../../../tests";
}
else
testPath = ptestPath;
return testPath;
}
void userDefinedTest(string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests)
{
for (int i = 1; i < boost::unit_test::framework::master_test_suite().argc; ++i)

2
test/TestHelper.h

@ -28,6 +28,7 @@
#include "JsonSpiritHeaders.h"
#include <libethereum/State.h>
#include <libevm/ExtVMFace.h>
#include <libtestutils/Common.h>
namespace dev
{
@ -138,7 +139,6 @@ void checkLog(eth::LogEntries _resultLogs, eth::LogEntries _expectedLogs);
void checkCallCreates(eth::Transactions _resultCallCreates, eth::Transactions _expectedCallCreates);
void executeTests(const std::string& _name, const std::string& _testPathAppendix, std::function<void(json_spirit::mValue&, bool)> doTests);
std::string getTestPath();
void userDefinedTest(std::string testTypeFlag, std::function<void(json_spirit::mValue&, bool)> doTests);
RLPStream createRLPStreamFromTransactionFields(json_spirit::mObject& _tObj);
eth::LastHashes lastHashes(u256 _currentBlockNumber);

117
test/TestUtils.cpp

@ -0,0 +1,117 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file TestUtils.cpp
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#include <thread>
#include <boost/test/unit_test.hpp>
#include <boost/filesystem.hpp>
#include <libtestutils/BlockChainLoader.h>
#include <libtestutils/FixedClient.h>
#include "TestUtils.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::test;
namespace dev
{
namespace test
{
bool getCommandLineOption(std::string const& _name);
std::string getCommandLineArgument(std::string const& _name, bool _require = false);
}
}
bool dev::test::getCommandLineOption(string const& _name)
{
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
bool result = false;
for (auto i = 0; !result && i < argc; ++i)
result = _name == argv[i];
return result;
}
std::string dev::test::getCommandLineArgument(string const& _name, bool _require)
{
auto argc = boost::unit_test::framework::master_test_suite().argc;
auto argv = boost::unit_test::framework::master_test_suite().argv;
for (auto i = 1; i < argc; ++i)
{
string str = argv[i];
if (_name == str.substr(0, _name.size()))
return str.substr(str.find("=") + 1);
}
if (_require)
BOOST_ERROR("Failed getting command line argument: " << _name << " from: " << argv);
return "";
}
LoadTestFileFixture::LoadTestFileFixture()
{
m_json = loadJsonFromFile(toTestFilePath(getCommandLineArgument("--eth_testfile")));
}
void ParallelFixture::enumerateThreads(std::function<void()> callback) const
{
size_t threadsCount = std::stoul(getCommandLineArgument("--eth_threads"), nullptr, 10);
vector<thread> workers;
for (size_t i = 0; i < threadsCount; i++)
workers.emplace_back(callback);
for_each(workers.begin(), workers.end(), [](thread &t)
{
t.join();
});
}
void BlockChainFixture::enumerateBlockchains(std::function<void(Json::Value const&, dev::eth::BlockChain const&, State state)> callback) const
{
for (string const& name: m_json.getMemberNames())
{
BlockChainLoader bcl(m_json[name]);
callback(m_json[name], bcl.bc(), bcl.state());
}
}
void ClientBaseFixture::enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const
{
enumerateBlockchains([&callback](Json::Value const& _json, BlockChain const& _bc, State _state) -> void
{
FixedClient client(_bc, _state);
callback(_json, client);
});
}
void ParallelClientBaseFixture::enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const
{
ClientBaseFixture::enumerateClients([this, &callback](Json::Value const& _json, dev::eth::ClientBase& _client) -> void
{
// json is being copied here
enumerateThreads([callback, _json, &_client]() -> void
{
callback(_json, _client);
});
});
}

82
test/TestUtils.h

@ -0,0 +1,82 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
/** @file TestUtils.h
* @author Marek Kotewicz <marek@ethdev.com>
* @date 2015
*/
#pragma once
#include <functional>
#include <string>
#include <json/json.h>
#include <libethereum/BlockChain.h>
#include <libethereum/ClientBase.h>
namespace dev
{
namespace test
{
// should be used for multithread tests
static SharedMutex x_boostTest;
#define ETH_CHECK_EQUAL(x, y) { dev::WriteGuard(x_boostTest); BOOST_CHECK_EQUAL(x, y); }
#define ETH_CHECK_EQUAL_COLLECTIONS(xb, xe, yb, ye) { dev::WriteGuard(x_boostTest); BOOST_CHECK_EQUAL_COLLECTIONS(xb, xe, yb, ye); }
#define ETH_REQUIRE(x) { dev::WriteGuard(x_boostTest); BOOST_REQUIRE(x); }
struct LoadTestFileFixture
{
LoadTestFileFixture();
protected:
Json::Value m_json;
};
struct ParallelFixture
{
void enumerateThreads(std::function<void()> callback) const;
};
struct BlockChainFixture: public LoadTestFileFixture
{
void enumerateBlockchains(std::function<void(Json::Value const&, dev::eth::BlockChain const&, dev::eth::State state)> callback) const;
};
struct ClientBaseFixture: public BlockChainFixture
{
void enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const;
};
// important BOOST TEST do have problems with thread safety!!!
// BOOST_CHECK is not thread safe
// BOOST_MESSAGE is not thread safe
// http://boost.2283326.n4.nabble.com/Is-boost-test-thread-safe-td3471644.html
// http://lists.boost.org/boost-users/2010/03/57691.php
// worth reading
// https://codecrafter.wordpress.com/2012/11/01/c-unit-test-framework-adapter-part-3/
struct ParallelClientBaseFixture: public ClientBaseFixture, public ParallelFixture
{
void enumerateClients(std::function<void(Json::Value const&, dev::eth::ClientBase&)> callback) const;
};
struct JsonRpcFixture: public ClientBaseFixture
{
};
}
}
Loading…
Cancel
Save