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 #include <QtTest/QtTestWidgets>
31 #include <QtTest/QtTestGui>
32 #include <new>
33 #include <string>
34 #include <univalue.h>
35 
36 namespace {
37 //! Call getblockchaininfo RPC and check first field of JSON output.
TestRpcCommand(RPCConsole * console)38 void TestRpcCommand(RPCConsole* console)
39 {
40     QEventLoop loop;
41     QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
42     QObject::connect(messagesWidget, &QTextEdit::textChanged, &loop, &QEventLoop::quit);
43     QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
44     QTest::keyClicks(lineEdit, "getblockchaininfo");
45     QTest::keyClick(lineEdit, Qt::Key_Return);
46     loop.exec();
47     QString output = messagesWidget->toPlainText();
48     UniValue value;
49     value.read(output.right(output.size() - output.lastIndexOf(QChar::ObjectReplacementCharacter) - 1).toStdString());
50     QCOMPARE(value["chain"].get_str(), std::string("regtest"));
51 }
52 } // namespace
53 
54 //! Entry point for BitcoinApplication tests.
appTests()55 void AppTests::appTests()
56 {
57 #ifdef Q_OS_MAC
58     if (QApplication::platformName() == "minimal") {
59         // Disable for mac on "minimal" platform to avoid crashes inside the Qt
60         // framework when it tries to look up unimplemented cocoa functions,
61         // and fails to handle returned nulls
62         // (https://bugreports.qt.io/browse/QTBUG-49686).
63         QWARN("Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
64               "with 'test_litecoin-qt -platform cocoa' on mac, or else use a linux or windows build.");
65         return;
66     }
67 #endif
68 
69     m_app.parameterSetup();
70     m_app.createOptionsModel(true /* reset settings */);
71     QScopedPointer<const NetworkStyle> style(
72         NetworkStyle::instantiate(QString::fromStdString(Params().NetworkIDString())));
73     m_app.setupPlatformStyle();
74     m_app.createWindow(style.data());
75     connect(&m_app, &BitcoinApplication::windowShown, this, &AppTests::guiTests);
76     expectCallback("guiTests");
77     m_app.baseInitialize();
78     m_app.requestInitialize();
79     m_app.exec();
80     m_app.requestShutdown();
81     m_app.exec();
82 
83     // Reset global state to avoid interfering with later tests.
84     AbortShutdown();
85     UnloadBlockIndex();
86 }
87 
88 //! Entry point for BitcoinGUI tests.
guiTests(BitcoinGUI * window)89 void AppTests::guiTests(BitcoinGUI* window)
90 {
91     HandleCallback callback{"guiTests", *this};
92     connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests);
93     expectCallback("consoleTests");
94     QAction* action = window->findChild<QAction*>("openRPCConsoleAction");
95     action->activate(QAction::Trigger);
96 }
97 
98 //! Entry point for RPCConsole tests.
consoleTests(RPCConsole * console)99 void AppTests::consoleTests(RPCConsole* console)
100 {
101     HandleCallback callback{"consoleTests", *this};
102     TestRpcCommand(console);
103 }
104 
105 //! Destructor to shut down after the last expected callback completes.
~HandleCallback()106 AppTests::HandleCallback::~HandleCallback()
107 {
108     auto& callbacks = m_app_tests.m_callbacks;
109     auto it = callbacks.find(m_callback);
110     assert(it != callbacks.end());
111     callbacks.erase(it);
112     if (callbacks.empty()) {
113         m_app_tests.m_app.quit();
114     }
115 }
116