/ src / qt / test / apptests.cpp
apptests.cpp
  1  // Copyright (c) 2018-present 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 <key.h>
  9  #include <logging.h>
 10  #include <qt/bitcoin.h>
 11  #include <qt/bitcoingui.h>
 12  #include <qt/networkstyle.h>
 13  #include <qt/rpcconsole.h>
 14  #include <test/util/setup_common.h>
 15  #include <validation.h>
 16  
 17  #include <QAction>
 18  #include <QLineEdit>
 19  #include <QRegularExpression>
 20  #include <QScopedPointer>
 21  #include <QSignalSpy>
 22  #include <QString>
 23  #include <QTest>
 24  #include <QTextEdit>
 25  #include <QtGlobal>
 26  #include <QtTest/QtTestWidgets>
 27  #include <QtTest/QtTestGui>
 28  
 29  namespace {
 30  //! Regex find a string group inside of the console output
 31  QString FindInConsole(const QString& output, const QString& pattern)
 32  {
 33      const QRegularExpression re(pattern);
 34      return re.match(output).captured(1);
 35  }
 36  
 37  //! Call getblockchaininfo RPC and check first field of JSON output.
 38  void TestRpcCommand(RPCConsole* console)
 39  {
 40      QTextEdit* messagesWidget = console->findChild<QTextEdit*>("messagesWidget");
 41      QLineEdit* lineEdit = console->findChild<QLineEdit*>("lineEdit");
 42      QSignalSpy mw_spy(messagesWidget, &QTextEdit::textChanged);
 43      QVERIFY(mw_spy.isValid());
 44      QTest::keyClicks(lineEdit, "getblockchaininfo");
 45      QTest::keyClick(lineEdit, Qt::Key_Return);
 46      QVERIFY(mw_spy.wait(1000));
 47      QCOMPARE(mw_spy.count(), 4);
 48      const QString output = messagesWidget->toPlainText();
 49      const QString pattern = QStringLiteral("\"chain\": \"(\\w+)\"");
 50      QCOMPARE(FindInConsole(output, pattern), QString("regtest"));
 51  }
 52  } // namespace
 53  
 54  //! Entry point for BitcoinApplication tests.
 55  void AppTests::appTests()
 56  {
 57  #ifdef Q_OS_MACOS
 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          qWarning() << "Skipping AppTests on mac build with 'minimal' platform set due to Qt bugs. To run AppTests, invoke "
 64                        "with 'QT_QPA_PLATFORM=cocoa test_bitcoin-qt' on mac, or else use a linux or windows build.";
 65          return;
 66      }
 67  #endif
 68  
 69      qRegisterMetaType<interfaces::BlockAndHeaderTipInfo>("interfaces::BlockAndHeaderTipInfo");
 70      m_app.parameterSetup();
 71      QVERIFY(m_app.createOptionsModel(/*resetSettings=*/true));
 72      QScopedPointer<const NetworkStyle> style(NetworkStyle::instantiate(Params().GetChainType()));
 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      LogInstance().DisconnectTestLogger();
 85  }
 86  
 87  //! Entry point for BitcoinGUI tests.
 88  void AppTests::guiTests(BitcoinGUI* window)
 89  {
 90      HandleCallback callback{"guiTests", *this};
 91      connect(window, &BitcoinGUI::consoleShown, this, &AppTests::consoleTests);
 92      expectCallback("consoleTests");
 93      QAction* action = window->findChild<QAction*>("openRPCConsoleAction");
 94      action->activate(QAction::Trigger);
 95  }
 96  
 97  //! Entry point for RPCConsole tests.
 98  void AppTests::consoleTests(RPCConsole* console)
 99  {
100      HandleCallback callback{"consoleTests", *this};
101      TestRpcCommand(console);
102  }
103  
104  //! Destructor to shut down after the last expected callback completes.
105  AppTests::HandleCallback::~HandleCallback()
106  {
107      auto& callbacks = m_app_tests.m_callbacks;
108      auto it = callbacks.find(m_callback);
109      assert(it != callbacks.end());
110      callbacks.erase(it);
111      if (callbacks.empty()) {
112          m_app_tests.m_app.exit(0);
113      }
114  }