mirror of
https://github.com/kvazar-network/kevacoin.git
synced 2025-09-13 15:32:05 +00:00

A few code changes were needed to accompany the test: * Adding setObjectName() calls for a few Qt controls to make them easily accessible from the test. * Calling contextMenu->popup() instead of contextMenu->exec() to open the transaction list context menu without blocking the test thread. * Opening the context menu at the contextualMenu event point rather than the cursor position (this change was not strictly needed to make the test work, but is more correct). * Updating the bumped transaction row with showTransaction=true instead of false. This is needed to prevent the bumped tx from being hidden, so the last part of the test which attempts to bump the bumped tx can work. (Technically this change is a more general bugfix not limited to the testing environment, but the bug doesn't happen outside of the testing environment because in the full Qt client, a queued NotifyTransactionChanged notification causes the row to be updated twice, first with showTransaction=false, then immediately after with showTransaction=true.)
186 lines
7.3 KiB
C++
186 lines
7.3 KiB
C++
#include "wallettests.h"
|
|
|
|
#include "qt/bitcoinamountfield.h"
|
|
#include "qt/callback.h"
|
|
#include "qt/optionsmodel.h"
|
|
#include "qt/platformstyle.h"
|
|
#include "qt/qvalidatedlineedit.h"
|
|
#include "qt/sendcoinsdialog.h"
|
|
#include "qt/sendcoinsentry.h"
|
|
#include "qt/transactiontablemodel.h"
|
|
#include "qt/transactionview.h"
|
|
#include "qt/walletmodel.h"
|
|
#include "test/test_bitcoin.h"
|
|
#include "validation.h"
|
|
#include "wallet/wallet.h"
|
|
|
|
#include <QAbstractButton>
|
|
#include <QAction>
|
|
#include <QApplication>
|
|
#include <QCheckBox>
|
|
#include <QPushButton>
|
|
#include <QTimer>
|
|
#include <QVBoxLayout>
|
|
|
|
namespace
|
|
{
|
|
//! Press "Ok" button in message box dialog.
|
|
void ConfirmMessage(QString* text = nullptr)
|
|
{
|
|
QTimer::singleShot(0, makeCallback([text](Callback* callback) {
|
|
for (QWidget* widget : QApplication::topLevelWidgets()) {
|
|
if (widget->inherits("QMessageBox")) {
|
|
QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
|
|
if (text) *text = messageBox->text();
|
|
messageBox->defaultButton()->click();
|
|
}
|
|
}
|
|
delete callback;
|
|
}), SLOT(call()));
|
|
}
|
|
|
|
//! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
|
|
void ConfirmSend(QString* text = nullptr, bool cancel = false)
|
|
{
|
|
QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
|
|
for (QWidget* widget : QApplication::topLevelWidgets()) {
|
|
if (widget->inherits("SendConfirmationDialog")) {
|
|
SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
|
|
if (text) *text = dialog->text();
|
|
QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
|
|
button->setEnabled(true);
|
|
button->click();
|
|
}
|
|
}
|
|
delete callback;
|
|
}), SLOT(call()));
|
|
}
|
|
|
|
//! Send coins to address and return txid.
|
|
uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf)
|
|
{
|
|
QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
|
|
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
|
|
entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(address.ToString()));
|
|
entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
|
|
sendCoinsDialog.findChild<QFrame*>("frameFee")
|
|
->findChild<QFrame*>("frameFeeSelection")
|
|
->findChild<QCheckBox*>("optInRBF")
|
|
->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
|
|
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 {};
|
|
}
|
|
|
|
//! Invoke bumpfee on txid and check results.
|
|
void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
|
|
{
|
|
QTableView* table = view.findChild<QTableView*>("transactionView");
|
|
QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
|
|
QVERIFY2(index.isValid(), "Could not find BumpFee txid");
|
|
|
|
// Select row in table, invoke context menu, and make sure bumpfee action is
|
|
// enabled or disabled as expected.
|
|
QAction* action = view.findChild<QAction*>("bumpFeeAction");
|
|
table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
|
|
action->setEnabled(expectDisabled);
|
|
table->customContextMenuRequested({});
|
|
QCOMPARE(action->isEnabled(), !expectDisabled);
|
|
|
|
action->setEnabled(true);
|
|
QString text;
|
|
if (expectError.empty()) {
|
|
ConfirmSend(&text, cancel);
|
|
} else {
|
|
ConfirmMessage(&text);
|
|
}
|
|
action->trigger();
|
|
QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
|
|
}
|
|
|
|
//! 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 TestSendCoins()
|
|
{
|
|
// 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()));
|
|
}
|
|
bitdb.MakeMock();
|
|
std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
|
|
CWallet wallet(std::move(dbw));
|
|
bool firstRun;
|
|
wallet.LoadWallet(firstRun);
|
|
{
|
|
LOCK(wallet.cs_wallet);
|
|
wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
|
|
wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
|
|
}
|
|
wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
|
|
wallet.SetBroadcastTransactions(true);
|
|
|
|
// Create widgets for sending coins and listing transactions.
|
|
std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
|
|
SendCoinsDialog sendCoinsDialog(platformStyle.get());
|
|
TransactionView transactionView(platformStyle.get());
|
|
OptionsModel optionsModel;
|
|
WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
|
|
sendCoinsDialog.setModel(&walletModel);
|
|
transactionView.setModel(&walletModel);
|
|
|
|
// Send two transactions, and verify they are added to transaction list.
|
|
TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
|
|
QCOMPARE(transactionTableModel->rowCount({}), 105);
|
|
uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 5 * COIN, false /* rbf */);
|
|
uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CBitcoinAddress(CKeyID()), 10 * COIN, true /* rbf */);
|
|
QCOMPARE(transactionTableModel->rowCount({}), 107);
|
|
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
|
|
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
|
|
|
|
// Call bumpfee. Test disabled, canceled, enabled, then failing cases.
|
|
BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
|
|
BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
|
|
BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
|
|
BumpFee(transactionView, txid2, false /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
|
|
|
|
bitdb.Flush(true);
|
|
bitdb.Reset();
|
|
}
|
|
|
|
}
|
|
|
|
void WalletTests::walletTests()
|
|
{
|
|
TestSendCoins();
|
|
}
|