88#include " qt/sendcoinsdialog.h"
99#include " qt/sendcoinsentry.h"
1010#include " qt/transactiontablemodel.h"
11+ #include " qt/transactionview.h"
1112#include " qt/walletmodel.h"
1213#include " test/test_bitcoin.h"
1314#include " validation.h"
1415#include " wallet/wallet.h"
1516
1617#include < QAbstractButton>
18+ #include < QAction>
1719#include < QApplication>
20+ #include < QCheckBox>
21+ #include < QPushButton>
1822#include < QTimer>
1923#include < QVBoxLayout>
2024
2125namespace
2226{
23- // ! Press "Yes " button in modal send confirmation dialog.
24- void ConfirmSend ( )
27+ // ! Press "Ok " button in message box dialog.
28+ void ConfirmMessage (QString* text = nullptr )
2529{
26- QTimer::singleShot (0 , makeCallback ([](Callback* callback) {
30+ QTimer::singleShot (0 , makeCallback ([text](Callback* callback) {
31+ for (QWidget* widget : QApplication::topLevelWidgets ()) {
32+ if (widget->inherits (" QMessageBox" )) {
33+ QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
34+ if (text) *text = messageBox->text ();
35+ messageBox->defaultButton ()->click ();
36+ }
37+ }
38+ delete callback;
39+ }), SLOT (call ()));
40+ }
41+
42+ // ! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
43+ void ConfirmSend (QString* text = nullptr , bool cancel = false )
44+ {
45+ QTimer::singleShot (0 , makeCallback ([text, cancel](Callback* callback) {
2746 for (QWidget* widget : QApplication::topLevelWidgets ()) {
2847 if (widget->inherits (" SendConfirmationDialog" )) {
2948 SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
30- QAbstractButton* button = dialog->button (QMessageBox::Yes);
49+ if (text) *text = dialog->text ();
50+ QAbstractButton* button = dialog->button (cancel ? QMessageBox::Cancel : QMessageBox::Yes);
3151 button->setEnabled (true );
3252 button->click ();
3353 }
@@ -37,12 +57,16 @@ void ConfirmSend()
3757}
3858
3959// ! Send coins to address and return txid.
40- uint256 SendCoins (CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount)
60+ uint256 SendCoins (CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CBitcoinAddress& address, CAmount amount, bool rbf )
4161{
4262 QVBoxLayout* entries = sendCoinsDialog.findChild <QVBoxLayout*>(" entries" );
4363 SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt (0 )->widget ());
4464 entry->findChild <QValidatedLineEdit*>(" payTo" )->setText (QString::fromStdString (address.ToString ()));
4565 entry->findChild <BitcoinAmountField*>(" payAmount" )->setValue (amount);
66+ sendCoinsDialog.findChild <QFrame*>(" frameFee" )
67+ ->findChild <QFrame*>(" frameFeeSelection" )
68+ ->findChild <QCheckBox*>(" optInRBF" )
69+ ->setCheckState (rbf ? Qt::Checked : Qt::Unchecked);
4670 uint256 txid;
4771 boost::signals2::scoped_connection c (wallet.NotifyTransactionChanged .connect ([&txid](CWallet*, const uint256& hash, ChangeType status) {
4872 if (status == CT_NEW) txid = hash;
@@ -65,6 +89,31 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
6589 }
6690 return {};
6791}
92+
93+ void BumpFee (TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
94+ {
95+ QTableView* table = view.findChild <QTableView*>(" transactionView" );
96+ QModelIndex index = FindTx (*table->selectionModel ()->model (), txid);
97+ QVERIFY2 (index.isValid (), " Could not find BumpFee txid" );
98+
99+ // Select row in table, invoke context menu, and make sure bumpfee action is
100+ // enabled or disabled as expected.
101+ QAction* action = view.findChild <QAction*>(" bumpFeeAction" );
102+ table->selectionModel ()->select (index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
103+ action->setEnabled (expectDisabled);
104+ table->customContextMenuRequested ({});
105+ QCOMPARE (action->isEnabled (), !expectDisabled);
106+
107+ action->setEnabled (true );
108+ QString text;
109+ if (expectError.empty ()) {
110+ ConfirmSend (&text, cancel);
111+ } else {
112+ ConfirmMessage (&text);
113+ }
114+ action->trigger ();
115+ QVERIFY (text.indexOf (QString::fromStdString (expectError)) != -1 );
116+ }
68117}
69118
70119// ! Simple qt wallet tests.
@@ -82,9 +131,11 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
82131// src/qt/test/test_bitcoin-qt -platform cocoa # macOS
83132void WalletTests::walletTests ()
84133{
85- // Set up wallet and chain with 101 blocks (1 mature block for spending).
134+ // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
86135 TestChain100Setup test;
87- test.CreateAndProcessBlock ({}, GetScriptForRawPubKey (test.coinbaseKey .GetPubKey ()));
136+ for (int i = 0 ; i < 5 ; ++i) {
137+ test.CreateAndProcessBlock ({}, GetScriptForRawPubKey (test.coinbaseKey .GetPubKey ()));
138+ }
88139 bitdb.MakeMock ();
89140 CWallet wallet (" wallet_test.dat" );
90141 bool firstRun;
@@ -100,19 +151,27 @@ void WalletTests::walletTests()
100151 // Create widgets for sending coins and listing transactions.
101152 std::unique_ptr<const PlatformStyle> platformStyle (PlatformStyle::instantiate (" other" ));
102153 SendCoinsDialog sendCoinsDialog (platformStyle.get ());
154+ TransactionView transactionView (platformStyle.get ());
103155 OptionsModel optionsModel;
104156 WalletModel walletModel (platformStyle.get (), &wallet, &optionsModel);
105157 sendCoinsDialog.setModel (&walletModel);
158+ transactionView.setModel (&walletModel);
106159
107160 // Send two transactions, and verify they are added to transaction list.
108161 TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel ();
109- QCOMPARE (transactionTableModel->rowCount ({}), 101 );
110- uint256 txid1 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 5 * COIN);
111- uint256 txid2 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 10 * COIN);
112- QCOMPARE (transactionTableModel->rowCount ({}), 103 );
162+ QCOMPARE (transactionTableModel->rowCount ({}), 105 );
163+ uint256 txid1 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 5 * COIN, false /* rbf */ );
164+ uint256 txid2 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 10 * COIN, true /* rbf */ );
165+ QCOMPARE (transactionTableModel->rowCount ({}), 107 );
113166 QVERIFY (FindTx (*transactionTableModel, txid1).isValid ());
114167 QVERIFY (FindTx (*transactionTableModel, txid2).isValid ());
115168
169+ // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
170+ BumpFee (transactionView, txid1, true /* expect disabled */ , " not BIP 125 replaceable" /* expected error */ , false /* cancel */ );
171+ BumpFee (transactionView, txid2, false /* expect disabled */ , {} /* expected error */ , true /* cancel */ );
172+ BumpFee (transactionView, txid2, false /* expect disabled */ , {} /* expected error */ , false /* cancel */ );
173+ BumpFee (transactionView, txid2, false /* expect disabled */ , " already bumped" /* expected error */ , false /* cancel */ );
174+
116175 bitdb.Flush (true );
117176 bitdb.Reset ();
118177}
0 commit comments