8
8
#include " qt/sendcoinsdialog.h"
9
9
#include " qt/sendcoinsentry.h"
10
10
#include " qt/transactiontablemodel.h"
11
+ #include " qt/transactionview.h"
11
12
#include " qt/walletmodel.h"
12
13
#include " test/test_bitcoin.h"
13
14
#include " validation.h"
14
15
#include " wallet/wallet.h"
15
16
16
17
#include < QAbstractButton>
18
+ #include < QAction>
17
19
#include < QApplication>
20
+ #include < QCheckBox>
21
+ #include < QPushButton>
18
22
#include < QTimer>
19
23
#include < QVBoxLayout>
20
24
21
25
namespace
22
26
{
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 )
25
29
{
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) {
27
46
for (QWidget* widget : QApplication::topLevelWidgets ()) {
28
47
if (widget->inherits (" SendConfirmationDialog" )) {
29
48
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);
31
51
button->setEnabled (true );
32
52
button->click ();
33
53
}
@@ -37,12 +57,16 @@ void ConfirmSend()
37
57
}
38
58
39
59
// ! 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 )
41
61
{
42
62
QVBoxLayout* entries = sendCoinsDialog.findChild <QVBoxLayout*>(" entries" );
43
63
SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt (0 )->widget ());
44
64
entry->findChild <QValidatedLineEdit*>(" payTo" )->setText (QString::fromStdString (address.ToString ()));
45
65
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);
46
70
uint256 txid;
47
71
boost::signals2::scoped_connection c (wallet.NotifyTransactionChanged .connect ([&txid](CWallet*, const uint256& hash, ChangeType status) {
48
72
if (status == CT_NEW) txid = hash;
@@ -66,6 +90,32 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
66
90
return {};
67
91
}
68
92
93
+ // ! Invoke bumpfee on txid and check results.
94
+ void BumpFee (TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
95
+ {
96
+ QTableView* table = view.findChild <QTableView*>(" transactionView" );
97
+ QModelIndex index = FindTx (*table->selectionModel ()->model (), txid);
98
+ QVERIFY2 (index.isValid (), " Could not find BumpFee txid" );
99
+
100
+ // Select row in table, invoke context menu, and make sure bumpfee action is
101
+ // enabled or disabled as expected.
102
+ QAction* action = view.findChild <QAction*>(" bumpFeeAction" );
103
+ table->selectionModel ()->select (index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
104
+ action->setEnabled (expectDisabled);
105
+ table->customContextMenuRequested ({});
106
+ QCOMPARE (action->isEnabled (), !expectDisabled);
107
+
108
+ action->setEnabled (true );
109
+ QString text;
110
+ if (expectError.empty ()) {
111
+ ConfirmSend (&text, cancel);
112
+ } else {
113
+ ConfirmMessage (&text);
114
+ }
115
+ action->trigger ();
116
+ QVERIFY (text.indexOf (QString::fromStdString (expectError)) != -1 );
117
+ }
118
+
69
119
// ! Simple qt wallet tests.
70
120
//
71
121
// Test widgets can be debugged interactively calling show() on them and
@@ -81,9 +131,11 @@ QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
81
131
// src/qt/test/test_bitcoin-qt -platform cocoa # macOS
82
132
void TestSendCoins ()
83
133
{
84
- // 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).
85
135
TestChain100Setup test;
86
- test.CreateAndProcessBlock ({}, GetScriptForRawPubKey (test.coinbaseKey .GetPubKey ()));
136
+ for (int i = 0 ; i < 5 ; ++i) {
137
+ test.CreateAndProcessBlock ({}, GetScriptForRawPubKey (test.coinbaseKey .GetPubKey ()));
138
+ }
87
139
bitdb.MakeMock ();
88
140
std::unique_ptr<CWalletDBWrapper> dbw (new CWalletDBWrapper (&bitdb, " wallet_test.dat" ));
89
141
CWallet wallet (std::move (dbw));
@@ -100,19 +152,27 @@ void TestSendCoins()
100
152
// Create widgets for sending coins and listing transactions.
101
153
std::unique_ptr<const PlatformStyle> platformStyle (PlatformStyle::instantiate (" other" ));
102
154
SendCoinsDialog sendCoinsDialog (platformStyle.get ());
155
+ TransactionView transactionView (platformStyle.get ());
103
156
OptionsModel optionsModel;
104
157
WalletModel walletModel (platformStyle.get (), &wallet, &optionsModel);
105
158
sendCoinsDialog.setModel (&walletModel);
159
+ transactionView.setModel (&walletModel);
106
160
107
161
// Send two transactions, and verify they are added to transaction list.
108
162
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 );
163
+ QCOMPARE (transactionTableModel->rowCount ({}), 105 );
164
+ uint256 txid1 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 5 * COIN, false /* rbf */ );
165
+ uint256 txid2 = SendCoins (wallet, sendCoinsDialog, CBitcoinAddress (CKeyID ()), 10 * COIN, true /* rbf */ );
166
+ QCOMPARE (transactionTableModel->rowCount ({}), 107 );
113
167
QVERIFY (FindTx (*transactionTableModel, txid1).isValid ());
114
168
QVERIFY (FindTx (*transactionTableModel, txid2).isValid ());
115
169
170
+ // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
171
+ BumpFee (transactionView, txid1, true /* expect disabled */ , " not BIP 125 replaceable" /* expected error */ , false /* cancel */ );
172
+ BumpFee (transactionView, txid2, false /* expect disabled */ , {} /* expected error */ , true /* cancel */ );
173
+ BumpFee (transactionView, txid2, false /* expect disabled */ , {} /* expected error */ , false /* cancel */ );
174
+ BumpFee (transactionView, txid2, false /* expect disabled */ , " already bumped" /* expected error */ , false /* cancel */ );
175
+
116
176
bitdb.Flush (true );
117
177
bitdb.Reset ();
118
178
}
0 commit comments