Skip to content

Commit 7e4bd19

Browse files
committed
Add BitcoinApplication & RPCConsole tests
Add test coverage for Qt initialization code & basic RPC console functionality.
1 parent ca20b65 commit 7e4bd19

File tree

11 files changed

+235
-24
lines changed

11 files changed

+235
-24
lines changed

src/Makefile.qt.include

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ RES_ICONS = \
303303

304304
BITCOIN_QT_BASE_CPP = \
305305
qt/bantablemodel.cpp \
306+
qt/bitcoin.cpp \
306307
qt/bitcoinaddressvalidator.cpp \
307308
qt/bitcoinamountfield.cpp \
308309
qt/bitcoingui.cpp \
@@ -383,6 +384,9 @@ qt_libbitcoinqt_a_OBJCXXFLAGS = $(AM_OBJCXXFLAGS) $(QT_PIE_FLAGS)
383384

384385
qt_libbitcoinqt_a_SOURCES = $(BITCOIN_QT_CPP) $(BITCOIN_QT_H) $(QT_FORMS_UI) \
385386
$(QT_QRC) $(QT_QRC_LOCALE) $(QT_TS) $(PROTOBUF_PROTO) $(RES_ICONS) $(RES_IMAGES) $(RES_MOVIES)
387+
if TARGET_DARWIN
388+
qt_libbitcoinqt_a_SOURCES += $(BITCOIN_MM)
389+
endif
386390

387391
nodist_qt_libbitcoinqt_a_SOURCES = $(QT_MOC_CPP) $(QT_MOC) $(PROTOBUF_CC) \
388392
$(PROTOBUF_H) $(QT_QRC_CPP) $(QT_QRC_LOCALE_CPP)
@@ -405,10 +409,7 @@ qt_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_QT_INCLUDE
405409
$(QT_INCLUDES) $(PROTOBUF_CFLAGS) $(QR_CFLAGS)
406410
qt_bitcoin_qt_CXXFLAGS = $(AM_CXXFLAGS) $(QT_PIE_FLAGS)
407411

408-
qt_bitcoin_qt_SOURCES = qt/bitcoin.cpp
409-
if TARGET_DARWIN
410-
qt_bitcoin_qt_SOURCES += $(BITCOIN_MM)
411-
endif
412+
qt_bitcoin_qt_SOURCES = qt/main.cpp
412413
if TARGET_WINDOWS
413414
qt_bitcoin_qt_SOURCES += $(BITCOIN_RC)
414415
endif

src/Makefile.qttest.include

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ bin_PROGRAMS += qt/test/test_bitcoin-qt
66
TESTS += qt/test/test_bitcoin-qt
77

88
TEST_QT_MOC_CPP = \
9+
qt/test/moc_apptests.cpp \
910
qt/test/moc_compattests.cpp \
1011
qt/test/moc_rpcnestedtests.cpp \
1112
qt/test/moc_uritests.cpp
@@ -22,6 +23,7 @@ endif # ENABLE_WALLET
2223

2324
TEST_QT_H = \
2425
qt/test/addressbooktests.h \
26+
qt/test/apptests.h \
2527
qt/test/compattests.h \
2628
qt/test/rpcnestedtests.h \
2729
qt/test/uritests.h \
@@ -40,6 +42,7 @@ qt_test_test_bitcoin_qt_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BITCOIN_
4042
$(QT_INCLUDES) $(QT_TEST_INCLUDES) $(PROTOBUF_CFLAGS)
4143

4244
qt_test_test_bitcoin_qt_SOURCES = \
45+
qt/test/apptests.cpp \
4346
qt/test/compattests.cpp \
4447
qt/test/rpcnestedtests.cpp \
4548
qt/test/test_main.cpp \

src/qt/bitcoin.cpp

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -72,11 +72,6 @@ Q_DECLARE_METATYPE(bool*)
7272
Q_DECLARE_METATYPE(CAmount)
7373
Q_DECLARE_METATYPE(uint256)
7474

75-
/** Translate string to current locale using Qt. */
76-
const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
77-
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
78-
};
79-
8075
static QString GetLangTerritory()
8176
{
8277
QSettings settings;
@@ -264,6 +259,11 @@ void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle)
264259
connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close);
265260
}
266261

262+
bool BitcoinApplication::baseInitialize()
263+
{
264+
return m_node.baseInitialize();
265+
}
266+
267267
void BitcoinApplication::startThread()
268268
{
269269
if(coreThread)
@@ -373,7 +373,7 @@ void BitcoinApplication::initializeResult(bool success)
373373
#ifdef ENABLE_BIP70
374374
PaymentServer::LoadRootCAs();
375375
#endif
376-
paymentServer->setOptionsModel(optionsModel);
376+
if (paymentServer) paymentServer->setOptionsModel(optionsModel);
377377
#endif
378378

379379
clientModel = new ClientModel(m_node, optionsModel);
@@ -402,16 +402,19 @@ void BitcoinApplication::initializeResult(bool success)
402402
window->show();
403403
}
404404
Q_EMIT splashFinished();
405+
Q_EMIT windowShown(window);
405406

406407
#ifdef ENABLE_WALLET
407408
// Now that initialization/startup is done, process any command-line
408409
// bitcoin: URIs or payment requests:
409-
connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
410-
connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
411-
connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
412-
window->message(title, message, style);
413-
});
414-
QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
410+
if (paymentServer) {
411+
connect(paymentServer, &PaymentServer::receivedPaymentRequest, window, &BitcoinGUI::handlePaymentRequest);
412+
connect(window, &BitcoinGUI::receivedURI, paymentServer, &PaymentServer::handleURIOrFile);
413+
connect(paymentServer, &PaymentServer::message, [this](const QString& title, const QString& message, unsigned int style) {
414+
window->message(title, message, style);
415+
});
416+
QTimer::singleShot(100, paymentServer, &PaymentServer::uiReady);
417+
}
415418
#endif
416419
pollShutdownTimer->start(200);
417420
} else {
@@ -454,7 +457,7 @@ static void SetupUIArgs()
454457
}
455458

456459
#ifndef BITCOIN_QT_TEST
457-
int main(int argc, char *argv[])
460+
int GuiMain(int argc, char* argv[])
458461
{
459462
#ifdef WIN32
460463
util::WinCmdLineArgs winArgs;
@@ -612,7 +615,7 @@ int main(int argc, char *argv[])
612615
// Perform base initialization before spinning up initialization/shutdown thread
613616
// This is acceptable because this function only contains steps that are quick to execute,
614617
// so the GUI thread won't be held up.
615-
if (node->baseInitialize()) {
618+
if (app.baseInitialize()) {
616619
app.requestInitialize();
617620
#if defined(Q_OS_WIN)
618621
WinShutdownMonitor::registerShutdownBlockReason(QObject::tr("%1 didn't yet exit safely...").arg(QObject::tr(PACKAGE_NAME)), (HWND)app.getMainWinId());

src/qt/bitcoin.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@ class BitcoinApplication: public QApplication
7171
void createWindow(const NetworkStyle *networkStyle);
7272
/// Create splash screen
7373
void createSplashScreen(const NetworkStyle *networkStyle);
74+
/// Basic initialization, before starting initialization/shutdown thread. Return true on success.
75+
bool baseInitialize();
7476

7577
/// Request core initialization
7678
void requestInitialize();
@@ -99,6 +101,7 @@ public Q_SLOTS:
99101
void requestedShutdown();
100102
void stopThread();
101103
void splashFinished();
104+
void windowShown(BitcoinGUI* window);
102105

103106
private:
104107
QThread *coreThread;
@@ -119,4 +122,6 @@ public Q_SLOTS:
119122
void startThread();
120123
};
121124

125+
int GuiMain(int argc, char* argv[]);
126+
122127
#endif // BITCOIN_QT_BITCOIN_H

src/qt/bitcoingui.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty
110110
* the central widget is the rpc console.
111111
*/
112112
setCentralWidget(rpcConsole);
113+
Q_EMIT consoleShown(rpcConsole);
113114
}
114115

115116
// Accept D&D of URIs
@@ -324,6 +325,7 @@ void BitcoinGUI::createActions()
324325
openRPCConsoleAction->setStatusTip(tr("Open debugging and diagnostic console"));
325326
// initially disable the debug window menu item
326327
openRPCConsoleAction->setEnabled(false);
328+
openRPCConsoleAction->setObjectName("openRPCConsoleAction");
327329

328330
usedSendingAddressesAction = new QAction(platformStyle->TextColorIcon(":/icons/address-book"), tr("&Sending addresses"), this);
329331
usedSendingAddressesAction->setStatusTip(tr("Show the list of used sending addresses and labels"));
@@ -642,9 +644,11 @@ void BitcoinGUI::createTrayIcon(const NetworkStyle *networkStyle)
642644
assert(QSystemTrayIcon::isSystemTrayAvailable());
643645

644646
#ifndef Q_OS_MAC
645-
trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
646-
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
647-
trayIcon->setToolTip(toolTip);
647+
if (QSystemTrayIcon::isSystemTrayAvailable()) {
648+
trayIcon = new QSystemTrayIcon(networkStyle->getTrayAndWindowIcon(), this);
649+
QString toolTip = tr("%1 client").arg(tr(PACKAGE_NAME)) + " " + networkStyle->getTitleAddText();
650+
trayIcon->setToolTip(toolTip);
651+
}
648652
#endif
649653
}
650654

@@ -724,6 +728,7 @@ void BitcoinGUI::aboutClicked()
724728
void BitcoinGUI::showDebugWindow()
725729
{
726730
GUIUtil::bringToFront(rpcConsole);
731+
Q_EMIT consoleShown(rpcConsole);
727732
}
728733

729734
void BitcoinGUI::showDebugWindowActivateConsole()

src/qt/bitcoingui.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,8 @@ class BitcoinGUI : public QMainWindow
187187
Q_SIGNALS:
188188
/** Signal raised when a URI was entered or dragged to the GUI */
189189
void receivedURI(const QString &uri);
190+
/** Signal raised when RPC console shown */
191+
void consoleShown(RPCConsole* console);
190192

191193
public Q_SLOTS:
192194
/** Set number of connections shown in the UI */

src/qt/main.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qt/bitcoin.h>
6+
7+
#include <QCoreApplication>
8+
9+
#include <functional>
10+
#include <string>
11+
12+
/** Translate string to current locale using Qt. */
13+
extern const std::function<std::string(const char*)> G_TRANSLATION_FUN = [](const char* psz) {
14+
return QCoreApplication::translate("bitcoin-core", psz).toStdString();
15+
};
16+
17+
int main(int argc, char* argv[]) { return GuiMain(argc, argv); }

src/qt/test/apptests.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#include <qt/test/apptests.h>
6+
7+
#include <chainparams.h>
8+
#include <init.h>
9+
#include <qt/bitcoin.h>
10+
#include <qt/bitcoingui.h>
11+
#include <qt/networkstyle.h>
12+
#include <qt/rpcconsole.h>
13+
#include <shutdown.h>
14+
#include <validation.h>
15+
16+
#if defined(HAVE_CONFIG_H)
17+
#include <config/bitcoin-config.h>
18+
#endif
19+
#ifdef ENABLE_WALLET
20+
#include <wallet/db.h>
21+
#endif
22+
23+
#include <QAction>
24+
#include <QEventLoop>
25+
#include <QLineEdit>
26+
#include <QScopedPointer>
27+
#include <QTest>
28+
#include <QTextEdit>
29+
#include <QtGlobal>
30+
#if QT_VERSION >= 0x050000
31+
#include <QtTest/QtTestWidgets>
32+
#endif
33+
#include <QtTest/QtTestGui>
34+
#include <new>
35+
#include <string>
36+
#include <univalue.h>
37+
38+
namespace {
39+
//! Call getblockchaininfo RPC and check first field of JSON output.
40+
void TestRpcCommand(RPCConsole* console)
41+
{
42+
QEventLoop loop;
43+
QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
44+
QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit);
45+
QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
46+
QTest::keyClicks(lineEdit, "getblockchaininfo");
47+
QTest::keyClick(lineEdit, Qt::Key_Return);
48+
loop.exec();
49+
QString output = messagesWidget->toPlainText();
50+
UniValue value;
51+
value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString());
52+
QCOMPARE(value["chain"].get_str(), std::string("regtest"));
53+
}
54+
} // namespace
55+
56+
//! Entry point for BitcoinApplication tests.
57+
void AppTests::appTests()
58+
{
59+
#ifdef Q_OS_MAC
60+
if (QApplication::platformName() == "minimal") {
61+
// Disable for mac on "minimal" platform to avoid crashes inside the Qt
62+
// framework when it tries to look up unimplemented cocoa functions,
63+
// and fails to handle returned nulls
64+
// (https://bugreports.qt.io/browse/QTBUG-49686).
65+
QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
66+
"with 'test_bitcoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
67+
return;
68+
}
69+
#endif
70+
71+
m_app.parameterSetup();
72+
m_app.createOptionsModel(true /* reset settings */);
73+
QScopedPointer<const NetworkStyle> style(
74+
NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
75+
m_app.setupPlatformStyle();
76+
m_app.createWindow(style.data());
77+
connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests);
78+
expectCallback("guiTests");
79+
m_app.baseInitialize();
80+
m_app.requestInitialize();
81+
m_app.exec();
82+
m_app.requestShutdown();
83+
m_app.exec();
84+
85+
// Reset global state to avoid interfering with later tests.
86+
AbortShutdown();
87+
UnloadBlockIndex();
88+
}
89+
90+
//! Entry point for BitcoinGUI tests.
91+
void AppTests::guiTests(BitcoinGUI* window)
92+
{
93+
HandleCallback callback{"guiTests", *this};
94+
connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests);
95+
expectCallback("consoleTests");
96+
QAction* action = window->findChild<QAction*>("openRPCConsoleAction");
97+
action->activate(QAction::Trigger);
98+
}
99+
100+
//! Entry point for RPCConsole tests.
101+
void AppTests::consoleTests(RPCConsole* console)
102+
{
103+
HandleCallback callback{"consoleTests", *this};
104+
TestRpcCommand(console);
105+
}
106+
107+
//! Destructor to shut down after the last expected callback completes.
108+
AppTests::HandleCallback::~HandleCallback()
109+
{
110+
auto& callbacks = m_app_tests.m_callbacks;
111+
auto it = callbacks.find(m_callback);
112+
assert(it != callbacks.end());
113+
callbacks.erase(it);
114+
if (callbacks.empty()) {
115+
m_app_tests.m_app.quit();
116+
}
117+
}

src/qt/test/apptests.h

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright (c) 2018 The Bitcoin Core developers
2+
// Distributed under the MIT software license, see the accompanying
3+
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
#ifndef BITCOIN_QT_TEST_APPTESTS_H
6+
#define BITCOIN_QT_TEST_APPTESTS_H
7+
8+
#include <QObject>
9+
#include <set>
10+
#include <string>
11+
#include <utility>
12+
13+
class BitcoinApplication;
14+
class BitcoinGUI;
15+
class RPCConsole;
16+
17+
class AppTests : public QObject
18+
{
19+
Q_OBJECT
20+
public:
21+
explicit AppTests(BitcoinApplication& app) : m_app(app) {}
22+
23+
private Q_SLOTS:
24+
void appTests();
25+
void guiTests(BitcoinGUI* window);
26+
void consoleTests(RPCConsole* console);
27+
28+
private:
29+
//! Add expected callback name to list of pending callbacks.
30+
void expectCallback(std::string callback) { m_callbacks.emplace(std::move(callback)); }
31+
32+
//! RAII helper to remove no-longer-pending callback.
33+
struct HandleCallback
34+
{
35+
std::string m_callback;
36+
AppTests& m_app_tests;
37+
~HandleCallback();
38+
};
39+
40+
//! Bitcoin application.
41+
BitcoinApplication& m_app;
42+
43+
//! Set of pending callback names. Used to track expected callbacks and shut
44+
//! down the app after the last callback has been handled and all tests have
45+
//! either run or thrown exceptions. This could be a simple int counter
46+
//! instead of a set of names, but the names might be useful for debugging.
47+
std::multiset<std::string> m_callbacks;
48+
};
49+
50+
#endif // BITCOIN_QT_TEST_APPTESTS_H

src/qt/test/rpcnestedtests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ void RPCNestedTests::rpcNestedTests()
4141

4242
TestingSetup test;
4343

44-
SetRPCWarmupFinished();
44+
if (RPCIsInWarmup(nullptr)) SetRPCWarmupFinished();
4545

4646
std::string result;
4747
std::string result2;

0 commit comments

Comments
 (0)