Merge #7783: [Qt] RPC-Console: support nested commands and simple value queries
1586044
[Qt] RPC-Console: support nested commands and simple value queries (Jonas Schnelli)
This commit is contained in:
commit
4335d5a41b
6 changed files with 300 additions and 71 deletions
|
@ -1,13 +1,16 @@
|
||||||
bin_PROGRAMS += qt/test/test_bitcoin-qt
|
bin_PROGRAMS += qt/test/test_bitcoin-qt
|
||||||
TESTS += qt/test/test_bitcoin-qt
|
TESTS += qt/test/test_bitcoin-qt
|
||||||
|
|
||||||
TEST_QT_MOC_CPP = qt/test/moc_uritests.cpp
|
TEST_QT_MOC_CPP = \
|
||||||
|
qt/test/moc_rpcnestedtests.cpp \
|
||||||
|
qt/test/moc_uritests.cpp
|
||||||
|
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
|
TEST_QT_MOC_CPP += qt/test/moc_paymentservertests.cpp
|
||||||
endif
|
endif
|
||||||
|
|
||||||
TEST_QT_H = \
|
TEST_QT_H = \
|
||||||
|
qt/test/rpcnestedtests.h \
|
||||||
qt/test/uritests.h \
|
qt/test/uritests.h \
|
||||||
qt/test/paymentrequestdata.h \
|
qt/test/paymentrequestdata.h \
|
||||||
qt/test/paymentservertests.h
|
qt/test/paymentservertests.h
|
||||||
|
@ -16,6 +19,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
|
||||||
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
|
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
|
||||||
|
|
||||||
qt_test_test_bitcoin_qt_SOURCES = \
|
qt_test_test_bitcoin_qt_SOURCES = \
|
||||||
|
qt/test/rpcnestedtests.cpp \
|
||||||
qt/test/test_main.cpp \
|
qt/test/test_main.cpp \
|
||||||
qt/test/uritests.cpp \
|
qt/test/uritests.cpp \
|
||||||
$(TEST_QT_H)
|
$(TEST_QT_H)
|
||||||
|
|
|
@ -113,9 +113,11 @@ public:
|
||||||
#include "rpcconsole.moc"
|
#include "rpcconsole.moc"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split shell command line into a list of arguments. Aims to emulate \c bash and friends.
|
* Split shell command line into a list of arguments and execute the command(s).
|
||||||
|
* Aims to emulate \c bash and friends.
|
||||||
*
|
*
|
||||||
* - Arguments are delimited with whitespace
|
* - Command nesting is possible with brackets [example: validateaddress(getnewaddress())]
|
||||||
|
* - Arguments are delimited with whitespace or comma
|
||||||
* - Extra whitespace at the beginning and end and between arguments will be ignored
|
* - Extra whitespace at the beginning and end and between arguments will be ignored
|
||||||
* - Text can be "double" or 'single' quoted
|
* - Text can be "double" or 'single' quoted
|
||||||
* - The backslash \c \ is used as escape character
|
* - The backslash \c \ is used as escape character
|
||||||
|
@ -123,11 +125,15 @@ public:
|
||||||
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
|
* - Within double quotes, only escape \c " and backslashes before a \c " or another backslash
|
||||||
* - Within single quotes, no escaping is possible and no special interpretation takes place
|
* - Within single quotes, no escaping is possible and no special interpretation takes place
|
||||||
*
|
*
|
||||||
* @param[out] args Parsed arguments will be appended to this list
|
* @param[out] result stringified Result from the executed command(chain)
|
||||||
* @param[in] strCommand Command line to split
|
* @param[in] strCommand Command line to split
|
||||||
*/
|
*/
|
||||||
bool parseCommandLine(std::vector<std::string> &args, const std::string &strCommand)
|
|
||||||
|
bool RPCConsole::RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand)
|
||||||
{
|
{
|
||||||
|
std::vector< std::vector<std::string> > stack;
|
||||||
|
stack.push_back(std::vector<std::string>());
|
||||||
|
|
||||||
enum CmdParseState
|
enum CmdParseState
|
||||||
{
|
{
|
||||||
STATE_EATING_SPACES,
|
STATE_EATING_SPACES,
|
||||||
|
@ -135,95 +141,180 @@ bool parseCommandLine(std::vector<std::string> &args, const std::string &strComm
|
||||||
STATE_SINGLEQUOTED,
|
STATE_SINGLEQUOTED,
|
||||||
STATE_DOUBLEQUOTED,
|
STATE_DOUBLEQUOTED,
|
||||||
STATE_ESCAPE_OUTER,
|
STATE_ESCAPE_OUTER,
|
||||||
STATE_ESCAPE_DOUBLEQUOTED
|
STATE_ESCAPE_DOUBLEQUOTED,
|
||||||
|
STATE_COMMAND_EXECUTED,
|
||||||
|
STATE_COMMAND_EXECUTED_INNER
|
||||||
} state = STATE_EATING_SPACES;
|
} state = STATE_EATING_SPACES;
|
||||||
std::string curarg;
|
std::string curarg;
|
||||||
Q_FOREACH(char ch, strCommand)
|
UniValue lastResult;
|
||||||
|
|
||||||
|
std::string strCommandTerminated = strCommand;
|
||||||
|
if (strCommandTerminated.back() != '\n')
|
||||||
|
strCommandTerminated += "\n";
|
||||||
|
for(char ch: strCommandTerminated)
|
||||||
{
|
{
|
||||||
switch(state)
|
switch(state)
|
||||||
{
|
{
|
||||||
case STATE_ARGUMENT: // In or after argument
|
case STATE_COMMAND_EXECUTED_INNER:
|
||||||
case STATE_EATING_SPACES: // Handle runs of whitespace
|
case STATE_COMMAND_EXECUTED:
|
||||||
switch(ch)
|
|
||||||
{
|
{
|
||||||
case '"': state = STATE_DOUBLEQUOTED; break;
|
bool breakParsing = true;
|
||||||
case '\'': state = STATE_SINGLEQUOTED; break;
|
switch(ch)
|
||||||
case '\\': state = STATE_ESCAPE_OUTER; break;
|
|
||||||
case ' ': case '\n': case '\t':
|
|
||||||
if(state == STATE_ARGUMENT) // Space ends argument
|
|
||||||
{
|
{
|
||||||
args.push_back(curarg);
|
case '[': curarg.clear(); state = STATE_COMMAND_EXECUTED_INNER; break;
|
||||||
curarg.clear();
|
default:
|
||||||
|
if (state == STATE_COMMAND_EXECUTED_INNER)
|
||||||
|
{
|
||||||
|
if (ch != ']')
|
||||||
|
{
|
||||||
|
// append char to the current argument (which is also used for the query command)
|
||||||
|
curarg += ch;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (curarg.size())
|
||||||
|
{
|
||||||
|
// if we have a value query, query arrays with index and objects with a string key
|
||||||
|
UniValue subelement;
|
||||||
|
if (lastResult.isArray())
|
||||||
|
{
|
||||||
|
for(char argch: curarg)
|
||||||
|
if (!std::isdigit(argch))
|
||||||
|
throw std::runtime_error("Invalid result query");
|
||||||
|
subelement = lastResult[atoi(curarg.c_str())];
|
||||||
|
}
|
||||||
|
else if (lastResult.isObject())
|
||||||
|
subelement = find_value(lastResult, curarg);
|
||||||
|
else
|
||||||
|
throw std::runtime_error("Invalid result query"); //no array or object: abort
|
||||||
|
lastResult = subelement;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = STATE_COMMAND_EXECUTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// don't break parsing when the char is required for the next argument
|
||||||
|
breakParsing = false;
|
||||||
|
|
||||||
|
// pop the stack and return the result to the current command arguments
|
||||||
|
stack.pop_back();
|
||||||
|
|
||||||
|
// don't stringify the json in case of a string to avoid doublequotes
|
||||||
|
if (lastResult.isStr())
|
||||||
|
curarg = lastResult.get_str();
|
||||||
|
else
|
||||||
|
curarg = lastResult.write(2);
|
||||||
|
|
||||||
|
// if we have a non empty result, use it as stack argument otherwise as general result
|
||||||
|
if (curarg.size())
|
||||||
|
{
|
||||||
|
if (stack.size())
|
||||||
|
stack.back().push_back(curarg);
|
||||||
|
else
|
||||||
|
strResult = curarg;
|
||||||
|
}
|
||||||
|
curarg.clear();
|
||||||
|
// assume eating space state
|
||||||
|
state = STATE_EATING_SPACES;
|
||||||
}
|
}
|
||||||
state = STATE_EATING_SPACES;
|
if (breakParsing)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case STATE_ARGUMENT: // In or after argument
|
||||||
|
case STATE_EATING_SPACES: // Handle runs of whitespace
|
||||||
|
switch(ch)
|
||||||
|
{
|
||||||
|
case '"': state = STATE_DOUBLEQUOTED; break;
|
||||||
|
case '\'': state = STATE_SINGLEQUOTED; break;
|
||||||
|
case '\\': state = STATE_ESCAPE_OUTER; break;
|
||||||
|
case '(': case ')': case '\n':
|
||||||
|
if (state == STATE_ARGUMENT)
|
||||||
|
{
|
||||||
|
if (ch == '(' && stack.size() && stack.back().size() > 0)
|
||||||
|
stack.push_back(std::vector<std::string>());
|
||||||
|
if (curarg.size())
|
||||||
|
{
|
||||||
|
// don't allow commands after executed commands on baselevel
|
||||||
|
if (!stack.size())
|
||||||
|
throw std::runtime_error("Invalid Syntax");
|
||||||
|
stack.back().push_back(curarg);
|
||||||
|
}
|
||||||
|
curarg.clear();
|
||||||
|
state = STATE_EATING_SPACES;
|
||||||
|
}
|
||||||
|
if ((ch == ')' || ch == '\n') && stack.size() > 0)
|
||||||
|
{
|
||||||
|
std::string strPrint;
|
||||||
|
// Convert argument list to JSON objects in method-dependent way,
|
||||||
|
// and pass it along with the method name to the dispatcher.
|
||||||
|
lastResult = tableRPC.execute(stack.back()[0], RPCConvertValues(stack.back()[0], std::vector<std::string>(stack.back().begin() + 1, stack.back().end())));
|
||||||
|
|
||||||
|
state = STATE_COMMAND_EXECUTED;
|
||||||
|
curarg.clear();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ' ': case ',': case '\t':
|
||||||
|
if(state == STATE_ARGUMENT) // Space ends argument
|
||||||
|
{
|
||||||
|
if (curarg.size())
|
||||||
|
stack.back().push_back(curarg);
|
||||||
|
curarg.clear();
|
||||||
|
}
|
||||||
|
state = STATE_EATING_SPACES;
|
||||||
|
break;
|
||||||
|
default: curarg += ch; state = STATE_ARGUMENT;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default: curarg += ch; state = STATE_ARGUMENT;
|
case STATE_SINGLEQUOTED: // Single-quoted string
|
||||||
}
|
switch(ch)
|
||||||
break;
|
|
||||||
case STATE_SINGLEQUOTED: // Single-quoted string
|
|
||||||
switch(ch)
|
|
||||||
{
|
{
|
||||||
case '\'': state = STATE_ARGUMENT; break;
|
case '\'': state = STATE_ARGUMENT; break;
|
||||||
default: curarg += ch;
|
default: curarg += ch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_DOUBLEQUOTED: // Double-quoted string
|
case STATE_DOUBLEQUOTED: // Double-quoted string
|
||||||
switch(ch)
|
switch(ch)
|
||||||
{
|
{
|
||||||
case '"': state = STATE_ARGUMENT; break;
|
case '"': state = STATE_ARGUMENT; break;
|
||||||
case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
|
case '\\': state = STATE_ESCAPE_DOUBLEQUOTED; break;
|
||||||
default: curarg += ch;
|
default: curarg += ch;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case STATE_ESCAPE_OUTER: // '\' outside quotes
|
case STATE_ESCAPE_OUTER: // '\' outside quotes
|
||||||
curarg += ch; state = STATE_ARGUMENT;
|
curarg += ch; state = STATE_ARGUMENT;
|
||||||
break;
|
break;
|
||||||
case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
|
case STATE_ESCAPE_DOUBLEQUOTED: // '\' in double-quoted text
|
||||||
if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
|
if(ch != '"' && ch != '\\') curarg += '\\'; // keep '\' for everything but the quote and '\' itself
|
||||||
curarg += ch; state = STATE_DOUBLEQUOTED;
|
curarg += ch; state = STATE_DOUBLEQUOTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch(state) // final state
|
switch(state) // final state
|
||||||
{
|
{
|
||||||
case STATE_EATING_SPACES:
|
case STATE_COMMAND_EXECUTED:
|
||||||
return true;
|
if (lastResult.isStr())
|
||||||
case STATE_ARGUMENT:
|
strResult = lastResult.get_str();
|
||||||
args.push_back(curarg);
|
else
|
||||||
return true;
|
strResult = lastResult.write(2);
|
||||||
default: // ERROR to end in one of the other states
|
case STATE_ARGUMENT:
|
||||||
return false;
|
case STATE_EATING_SPACES:
|
||||||
|
return true;
|
||||||
|
default: // ERROR to end in one of the other states
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RPCExecutor::request(const QString &command)
|
void RPCExecutor::request(const QString &command)
|
||||||
{
|
{
|
||||||
std::vector<std::string> args;
|
|
||||||
if(!parseCommandLine(args, command.toStdString()))
|
|
||||||
{
|
|
||||||
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(args.empty())
|
|
||||||
return; // Nothing to do
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string strPrint;
|
std::string result;
|
||||||
// Convert argument list to JSON objects in method-dependent way,
|
std::string executableCommand = command.toStdString() + "\n";
|
||||||
// and pass it along with the method name to the dispatcher.
|
if(!RPCConsole::RPCExecuteCommandLine(result, executableCommand))
|
||||||
UniValue result = tableRPC.execute(
|
{
|
||||||
args[0],
|
Q_EMIT reply(RPCConsole::CMD_ERROR, QString("Parse error: unbalanced ' or \""));
|
||||||
RPCConvertValues(args[0], std::vector<std::string>(args.begin() + 1, args.end())));
|
return;
|
||||||
|
}
|
||||||
// Format result reply
|
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(result));
|
||||||
if (result.isNull())
|
|
||||||
strPrint = "";
|
|
||||||
else if (result.isStr())
|
|
||||||
strPrint = result.get_str();
|
|
||||||
else
|
|
||||||
strPrint = result.write(2);
|
|
||||||
|
|
||||||
Q_EMIT reply(RPCConsole::CMD_REPLY, QString::fromStdString(strPrint));
|
|
||||||
}
|
}
|
||||||
catch (UniValue& objError)
|
catch (UniValue& objError)
|
||||||
{
|
{
|
||||||
|
|
|
@ -35,6 +35,8 @@ public:
|
||||||
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
|
explicit RPCConsole(const PlatformStyle *platformStyle, QWidget *parent);
|
||||||
~RPCConsole();
|
~RPCConsole();
|
||||||
|
|
||||||
|
static bool RPCExecuteCommandLine(std::string &strResult, const std::string &strCommand);
|
||||||
|
|
||||||
void setClientModel(ClientModel *model);
|
void setClientModel(ClientModel *model);
|
||||||
|
|
||||||
enum MessageClass {
|
enum MessageClass {
|
||||||
|
|
93
src/qt/test/rpcnestedtests.cpp
Normal file
93
src/qt/test/rpcnestedtests.cpp
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include "rpcnestedtests.h"
|
||||||
|
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "consensus/validation.h"
|
||||||
|
#include "main.h"
|
||||||
|
#include "rpc/register.h"
|
||||||
|
#include "rpc/server.h"
|
||||||
|
#include "rpcconsole.h"
|
||||||
|
#include "test/testutil.h"
|
||||||
|
#include "univalue.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include <boost/filesystem.hpp>
|
||||||
|
|
||||||
|
void RPCNestedTests::rpcNestedTests()
|
||||||
|
{
|
||||||
|
UniValue jsonRPCError;
|
||||||
|
|
||||||
|
// do some test setup
|
||||||
|
// could be moved to a more generic place when we add more tests on QT level
|
||||||
|
const CChainParams& chainparams = Params();
|
||||||
|
RegisterAllCoreRPCCommands(tableRPC);
|
||||||
|
ClearDatadirCache();
|
||||||
|
std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_bitcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
|
||||||
|
QDir dir(QString::fromStdString(path));
|
||||||
|
dir.mkpath(".");
|
||||||
|
mapArgs["-datadir"] = path;
|
||||||
|
//mempool.setSanityCheck(1.0);
|
||||||
|
pblocktree = new CBlockTreeDB(1 << 20, true);
|
||||||
|
pcoinsdbview = new CCoinsViewDB(1 << 23, true);
|
||||||
|
pcoinsTip = new CCoinsViewCache(pcoinsdbview);
|
||||||
|
InitBlockIndex(chainparams);
|
||||||
|
{
|
||||||
|
CValidationState state;
|
||||||
|
bool ok = ActivateBestChain(state, chainparams);
|
||||||
|
QVERIFY(ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetRPCWarmupFinished();
|
||||||
|
|
||||||
|
std::string result;
|
||||||
|
std::string result2;
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]"); //simple result filtering with path
|
||||||
|
QVERIFY(result=="main");
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
|
||||||
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
|
||||||
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
|
||||||
|
QVERIFY(result.substr(0,1) == "{");
|
||||||
|
|
||||||
|
#if QT_VERSION >= 0x050300
|
||||||
|
// do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
|
||||||
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
|
||||||
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
|
||||||
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
|
||||||
|
QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
|
||||||
|
#endif
|
||||||
|
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
|
||||||
|
QVERIFY(result == "null");
|
||||||
|
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
|
||||||
|
QVERIFY(result == result2);
|
||||||
|
(RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [], {} , 0 )")); //whitespace between parametres is allowed
|
||||||
|
QVERIFY(result == result2);
|
||||||
|
|
||||||
|
RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]");
|
||||||
|
QVERIFY(result == "4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b");
|
||||||
|
|
||||||
|
delete pcoinsTip;
|
||||||
|
delete pcoinsdbview;
|
||||||
|
delete pblocktree;
|
||||||
|
|
||||||
|
boost::filesystem::remove_all(boost::filesystem::path(path));
|
||||||
|
}
|
25
src/qt/test/rpcnestedtests.h
Normal file
25
src/qt/test/rpcnestedtests.h
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
|
||||||
|
#define BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QTest>
|
||||||
|
|
||||||
|
#include "txdb.h"
|
||||||
|
#include "txmempool.h"
|
||||||
|
|
||||||
|
class RPCNestedTests : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void rpcNestedTests();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CCoinsViewDB *pcoinsdbview;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITCOIN_QT_TEST_RPC_NESTED_TESTS_H
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright (c) 2009-2015 The Bitcoin Core developers
|
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
||||||
// Distributed under the MIT software license, see the accompanying
|
// Distributed under the MIT software license, see the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@
|
||||||
#include "config/bitcoin-config.h"
|
#include "config/bitcoin-config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "chainparams.h"
|
||||||
|
#include "key.h"
|
||||||
|
#include "rpcnestedtests.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "uritests.h"
|
#include "uritests.h"
|
||||||
|
|
||||||
|
@ -27,10 +30,17 @@ Q_IMPORT_PLUGIN(qtwcodecs)
|
||||||
Q_IMPORT_PLUGIN(qkrcodecs)
|
Q_IMPORT_PLUGIN(qkrcodecs)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern void noui_connect();
|
||||||
|
|
||||||
// This is all you need to run all the tests
|
// This is all you need to run all the tests
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
ECC_Start();
|
||||||
SetupEnvironment();
|
SetupEnvironment();
|
||||||
|
SetupNetworking();
|
||||||
|
SelectParams(CBaseChainParams::MAIN);
|
||||||
|
noui_connect();
|
||||||
|
|
||||||
bool fInvalid = false;
|
bool fInvalid = false;
|
||||||
|
|
||||||
// Don't remove this, it's needed to access
|
// Don't remove this, it's needed to access
|
||||||
|
@ -48,6 +58,10 @@ int main(int argc, char *argv[])
|
||||||
if (QTest::qExec(&test2) != 0)
|
if (QTest::qExec(&test2) != 0)
|
||||||
fInvalid = true;
|
fInvalid = true;
|
||||||
#endif
|
#endif
|
||||||
|
RPCNestedTests test3;
|
||||||
|
if (QTest::qExec(&test3) != 0)
|
||||||
|
fInvalid = true;
|
||||||
|
|
||||||
|
ECC_Stop();
|
||||||
return fInvalid;
|
return fInvalid;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue