diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 116917b588..2647c71cb3 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -1,146 +1,160 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include #include namespace { /** * Fill the edit address dialog box with data, submit it, and ensure that * the resulting message meets expectations. */ void EditAddressAndSubmit(EditAddressDialog *dialog, const QString &label, const QString &address, QString expected_msg) { QString warning_text; dialog->findChild("labelEdit")->setText(label); dialog->findChild("addressEdit")->setText(address); ConfirmMessage(&warning_text, 5); dialog->accept(); QCOMPARE(warning_text, expected_msg); } /** * Test adding various send addresses to the address book. * * There are three cases tested: * * - new_address: a new address which should add as a send address * successfully. * - existing_s_address: an existing sending address which won't add * successfully. * - existing_r_address: an existing receiving address which won't add * successfully. * * In each case, verify the resulting state of the address book and optionally * the warning message presented to the user. */ void TestAddAddressesToSendBook() { TestChain100Setup test; CWallet wallet(Params(), "mock", WalletDatabase::CreateMock()); bool firstRun; wallet.LoadWallet(firstRun); auto build_address = [&wallet]() { CKey key; key.MakeNewKey(true); CTxDestination dest(GetDestinationForKey( key.GetPubKey(), wallet.m_default_address_type)); return std::make_pair( dest, QString::fromStdString(EncodeCashAddr(dest, Params()))); }; CTxDestination r_key_dest, s_key_dest; // Add a preexisting "receive" entry in the address book. QString preexisting_r_address; QString r_label("already here (r)"); // Add a preexisting "send" entry in the address book. QString preexisting_s_address; QString s_label("already here (s)"); // Define a new address (which should add to the address book successfully). QString new_address; std::tie(r_key_dest, preexisting_r_address) = build_address(); std::tie(s_key_dest, preexisting_s_address) = build_address(); std::tie(std::ignore, new_address) = build_address(); { LOCK(wallet.cs_wallet); wallet.SetAddressBook(r_key_dest, r_label.toStdString(), "receive"); wallet.SetAddressBook(s_key_dest, s_label.toStdString(), "send"); } auto check_addbook_size = [&wallet](int expected_size) { QCOMPARE(static_cast(wallet.mapAddressBook.size()), expected_size); }; // We should start with the two addresses we added earlier and nothing else. check_addbook_size(2); // Initialize relevant QT models. std::unique_ptr platformStyle( PlatformStyle::instantiate("other")); auto node = interfaces::MakeNode(); OptionsModel optionsModel(*node); AddWallet(&wallet); WalletModel walletModel(std::move(node->getWallets()[0]), *node, platformStyle.get(), &optionsModel); RemoveWallet(&wallet); EditAddressDialog editAddressDialog(EditAddressDialog::NewSendingAddress); editAddressDialog.setModel(walletModel.getAddressTableModel()); EditAddressAndSubmit( &editAddressDialog, QString("uhoh"), preexisting_r_address, QString( "Address \"%1\" already exists as a receiving address with label " "\"%2\" and so cannot be added as a sending address.") .arg(preexisting_r_address) .arg(r_label)); check_addbook_size(2); EditAddressAndSubmit( &editAddressDialog, QString("uhoh, different"), preexisting_s_address, QString( "The entered address \"%1\" is already in the address book with " "label \"%2\".") .arg(preexisting_s_address) .arg(s_label)); check_addbook_size(2); // Submit a new address which should add successfully - we expect the // warning message to be blank. EditAddressAndSubmit(&editAddressDialog, QString("new"), new_address, QString("")); check_addbook_size(3); } } // namespace void AddressBookTests::addressBookTests() { +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN( + "Skipping AddressBookTests on mac build with 'minimal' platform " + "set due to Qt bugs. To run AppTests, invoke with 'test_bitcoin-qt " + "-platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif TestAddAddressesToSendBook(); } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 5c3c878c11..d9778a293e 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -1,248 +1,246 @@ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace { //! Press "Yes" or "Cancel" buttons in modal send confirmation dialog. void ConfirmSend(QString *text = nullptr, bool cancel = false) { QTimer::singleShot(0, Qt::PreciseTimer, [text, cancel]() { for (QWidget *widget : QApplication::topLevelWidgets()) { if (widget->inherits("SendConfirmationDialog")) { SendConfirmationDialog *dialog = qobject_cast(widget); if (text) { *text = dialog->text(); } QAbstractButton *button = dialog->button( cancel ? QMessageBox::Cancel : QMessageBox::Yes); button->setEnabled(true); button->click(); } } }); } //! Send coins to address and return txid. uint256 SendCoins(CWallet &wallet, SendCoinsDialog &sendCoinsDialog, const CTxDestination &address, Amount amount) { QVBoxLayout *entries = sendCoinsDialog.findChild("entries"); SendCoinsEntry *entry = qobject_cast(entries->itemAt(0)->widget()); entry->findChild("payTo")->setText( QString::fromStdString(EncodeCashAddr(address, Params()))); entry->findChild("payAmount")->setValue(amount); uint256 txid; boost::signals2::scoped_connection c = wallet.NotifyTransactionChanged.connect( [&txid](CWallet *, const uint256 &hash, ChangeType status) { if (status == CT_NEW) { txid = hash; } }); ConfirmSend(); QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked"); return txid; } //! Find index of txid in transaction list. QModelIndex FindTx(const QAbstractItemModel &model, const uint256 &txid) { QString hash = QString::fromStdString(txid.ToString()); int rows = model.rowCount({}); for (int row = 0; row < rows; ++row) { QModelIndex index = model.index(row, 0, {}); if (model.data(index, TransactionTableModel::TxHashRole) == hash) { return index; } } return {}; } //! Simple qt wallet tests. // // Test widgets can be debugged interactively calling show() on them and // manually running the event loop, e.g.: // // sendCoinsDialog.show(); // QEventLoop().exec(); // // This also requires overriding the default minimal Qt platform: // // src/qt/test/test_bitcoin-qt -platform xcb # Linux // src/qt/test/test_bitcoin-qt -platform windows # Windows // src/qt/test/test_bitcoin-qt -platform cocoa # macOS void TestGUI() { -#ifdef Q_OS_MAC - if (QApplication::platformName() == "minimal") { - // Disable for mac on "minimal" platform to avoid crashes inside the Qt - // framework when it tries to look up unimplemented cocoa functions, - // and fails to handle returned nulls - // (https://bugreports.qt.io/browse/QTBUG-49686). - QWARN("Skipping WalletTests on mac build with 'minimal' platform set " - "due to Qt bugs. To run AppTests, invoke " - "with 'test_bitcoin-qt -platform cocoa' on mac, or else use a " - "linux or windows build."); - return; - } -#endif - // Set up wallet and chain with 105 blocks (5 mature blocks for spending). TestChain100Setup test; for (int i = 0; i < 5; ++i) { test.CreateAndProcessBlock( {}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey())); } CWallet wallet(Params(), "mock", WalletDatabase::CreateMock()); bool firstRun; wallet.LoadWallet(firstRun); { LOCK(wallet.cs_wallet); wallet.SetAddressBook( GetDestinationForKey(test.coinbaseKey.GetPubKey(), wallet.m_default_address_type), "", "receive"); wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); } { LOCK(cs_main); WalletRescanReserver reserver(&wallet); reserver.reserve(); wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true); } wallet.SetBroadcastTransactions(true); // Create widgets for sending coins and listing transactions. std::unique_ptr platformStyle( PlatformStyle::instantiate("other")); auto node = interfaces::MakeNode(); OptionsModel optionsModel(*node); AddWallet(&wallet); WalletModel walletModel(std::move(node->getWallets().back()), *node, platformStyle.get(), &optionsModel); RemoveWallet(&wallet); // Send two transactions, and verify they are added to transaction list. SendCoinsDialog sendCoinsDialog(platformStyle.get(), &walletModel); TransactionTableModel *transactionTableModel = walletModel.getTransactionTableModel(); QCOMPARE(transactionTableModel->rowCount({}), 105); uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 5 * COIN); uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CTxDestination(CKeyID()), 10 * COIN); QCOMPARE(transactionTableModel->rowCount({}), 107); QVERIFY(FindTx(*transactionTableModel, txid1).isValid()); QVERIFY(FindTx(*transactionTableModel, txid2).isValid()); // Check current balance on OverviewPage OverviewPage overviewPage(platformStyle.get()); overviewPage.setWalletModel(&walletModel); QLabel *balanceLabel = overviewPage.findChild("labelBalance"); QString balanceText = balanceLabel->text(); int unit = walletModel.getOptionsModel()->getDisplayUnit(); Amount balance = walletModel.wallet().getBalance(); QString balanceComparison = BitcoinUnits::formatWithUnit( unit, balance, false, BitcoinUnits::separatorAlways); QCOMPARE(balanceText, balanceComparison); // Check Request Payment button ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get()); receiveCoinsDialog.setModel(&walletModel); RecentRequestsTableModel *requestTableModel = walletModel.getRecentRequestsTableModel(); // Label input QLineEdit *labelInput = receiveCoinsDialog.findChild("reqLabel"); labelInput->setText("TEST_LABEL_1"); // Amount input BitcoinAmountField *amountInput = receiveCoinsDialog.findChild("reqAmount"); amountInput->setValue(1 * SATOSHI); // Message input QLineEdit *messageInput = receiveCoinsDialog.findChild("reqMessage"); messageInput->setText("TEST_MESSAGE_1"); int initialRowCount = requestTableModel->rowCount({}); QPushButton *requestPaymentButton = receiveCoinsDialog.findChild("receiveButton"); requestPaymentButton->click(); for (QWidget *widget : QApplication::topLevelWidgets()) { if (widget->inherits("ReceiveRequestDialog")) { ReceiveRequestDialog *receiveRequestDialog = qobject_cast(widget); QTextEdit *rlist = receiveRequestDialog->QObject::findChild("outUri"); QString paymentText = rlist->toPlainText(); QStringList paymentTextList = paymentText.split('\n'); QCOMPARE(paymentTextList.at(0), QString("Payment information")); QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bchreg:")) != -1); QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1); QCOMPARE(paymentTextList.at(3), QString("Amount: 0.00000001 ") + QString::fromStdString(CURRENCY_UNIT)); QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1")); QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1")); } } // Clear button QPushButton *clearButton = receiveCoinsDialog.findChild("clearButton"); clearButton->click(); QCOMPARE(labelInput->text(), QString("")); QCOMPARE(amountInput->value(), Amount::zero()); QCOMPARE(messageInput->text(), QString("")); // Check addition to history int currentRowCount = requestTableModel->rowCount({}); QCOMPARE(currentRowCount, initialRowCount + 1); // Check Remove button QTableView *table = receiveCoinsDialog.findChild("recentRequestsView"); table->selectRow(currentRowCount - 1); QPushButton *removeRequestButton = receiveCoinsDialog.findChild("removeRequestButton"); removeRequestButton->click(); QCOMPARE(requestTableModel->rowCount({}), currentRowCount - 1); } } // namespace void WalletTests::walletTests() { +#ifdef Q_OS_MAC + if (QApplication::platformName() == "minimal") { + // Disable for mac on "minimal" platform to avoid crashes inside the Qt + // framework when it tries to look up unimplemented cocoa functions, + // and fails to handle returned nulls + // (https://bugreports.qt.io/browse/QTBUG-49686). + QWARN("Skipping WalletTests on mac build with 'minimal' platform set " + "due to Qt bugs. To run AppTests, invoke with 'test_bitcoin-qt " + "-platform cocoa' on mac, or else use a linux or windows build."); + return; + } +#endif TestGUI(); }