Merge #10574: Remove includes in .cpp files for things the corresponding .h file...
[bitcoinplatinum.git] / src / qt / test / wallettests.cpp
blob4b7c3bd726a6de1301c4e8a929d4da659552521e
1 #include <qt/test/wallettests.h>
3 #include <qt/bitcoinamountfield.h>
4 #include <qt/callback.h>
5 #include <qt/optionsmodel.h>
6 #include <qt/platformstyle.h>
7 #include <qt/qvalidatedlineedit.h>
8 #include <qt/sendcoinsdialog.h>
9 #include <qt/sendcoinsentry.h>
10 #include <qt/transactiontablemodel.h>
11 #include <qt/transactionview.h>
12 #include <qt/walletmodel.h>
13 #include <test/test_bitcoin.h>
14 #include <validation.h>
15 #include <wallet/wallet.h>
16 #include <qt/overviewpage.h>
17 #include <qt/receivecoinsdialog.h>
18 #include <qt/recentrequeststablemodel.h>
19 #include <qt/receiverequestdialog.h>
21 #include <QAbstractButton>
22 #include <QAction>
23 #include <QApplication>
24 #include <QCheckBox>
25 #include <QPushButton>
26 #include <QTimer>
27 #include <QVBoxLayout>
28 #include <QTextEdit>
29 #include <QListView>
30 #include <QDialogButtonBox>
32 namespace
34 //! Press "Ok" button in message box dialog.
35 void ConfirmMessage(QString* text = nullptr)
37 QTimer::singleShot(0, makeCallback([text](Callback* callback) {
38 for (QWidget* widget : QApplication::topLevelWidgets()) {
39 if (widget->inherits("QMessageBox")) {
40 QMessageBox* messageBox = qobject_cast<QMessageBox*>(widget);
41 if (text) *text = messageBox->text();
42 messageBox->defaultButton()->click();
45 delete callback;
46 }), SLOT(call()));
49 //! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
50 void ConfirmSend(QString* text = nullptr, bool cancel = false)
52 QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
53 for (QWidget* widget : QApplication::topLevelWidgets()) {
54 if (widget->inherits("SendConfirmationDialog")) {
55 SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
56 if (text) *text = dialog->text();
57 QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
58 button->setEnabled(true);
59 button->click();
62 delete callback;
63 }), SLOT(call()));
66 //! Send coins to address and return txid.
67 uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
69 QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
70 SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
71 entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
72 entry->findChild<BitcoinAmountField*>("payAmount")->setValue(amount);
73 sendCoinsDialog.findChild<QFrame*>("frameFee")
74 ->findChild<QFrame*>("frameFeeSelection")
75 ->findChild<QCheckBox*>("optInRBF")
76 ->setCheckState(rbf ? Qt::Checked : Qt::Unchecked);
77 uint256 txid;
78 boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
79 if (status == CT_NEW) txid = hash;
80 }));
81 ConfirmSend();
82 QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
83 return txid;
86 //! Find index of txid in transaction list.
87 QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
89 QString hash = QString::fromStdString(txid.ToString());
90 int rows = model.rowCount({});
91 for (int row = 0; row < rows; ++row) {
92 QModelIndex index = model.index(row, 0, {});
93 if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
94 return index;
97 return {};
100 //! Request context menu (call method that is public in qt5, but protected in qt4).
101 void RequestContextMenu(QWidget* widget)
103 class Qt4Hack : public QWidget
105 public:
106 using QWidget::customContextMenuRequested;
108 static_cast<Qt4Hack*>(widget)->customContextMenuRequested({});
111 //! Invoke bumpfee on txid and check results.
112 void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
114 QTableView* table = view.findChild<QTableView*>("transactionView");
115 QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
116 QVERIFY2(index.isValid(), "Could not find BumpFee txid");
118 // Select row in table, invoke context menu, and make sure bumpfee action is
119 // enabled or disabled as expected.
120 QAction* action = view.findChild<QAction*>("bumpFeeAction");
121 table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
122 action->setEnabled(expectDisabled);
123 RequestContextMenu(table);
124 QCOMPARE(action->isEnabled(), !expectDisabled);
126 action->setEnabled(true);
127 QString text;
128 if (expectError.empty()) {
129 ConfirmSend(&text, cancel);
130 } else {
131 ConfirmMessage(&text);
133 action->trigger();
134 QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
137 //! Simple qt wallet tests.
139 // Test widgets can be debugged interactively calling show() on them and
140 // manually running the event loop, e.g.:
142 // sendCoinsDialog.show();
143 // QEventLoop().exec();
145 // This also requires overriding the default minimal Qt platform:
147 // src/qt/test/test_bitcoin-qt -platform xcb # Linux
148 // src/qt/test/test_bitcoin-qt -platform windows # Windows
149 // src/qt/test/test_bitcoin-qt -platform cocoa # macOS
150 void TestGUI()
152 // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
153 TestChain100Setup test;
154 for (int i = 0; i < 5; ++i) {
155 test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
157 bitdb.MakeMock();
158 std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
159 CWallet wallet(std::move(dbw));
160 bool firstRun;
161 wallet.LoadWallet(firstRun);
163 LOCK(wallet.cs_wallet);
164 wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
165 wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
168 LOCK(cs_main);
169 wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true);
171 wallet.SetBroadcastTransactions(true);
173 // Create widgets for sending coins and listing transactions.
174 std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
175 SendCoinsDialog sendCoinsDialog(platformStyle.get());
176 TransactionView transactionView(platformStyle.get());
177 OptionsModel optionsModel;
178 WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
179 sendCoinsDialog.setModel(&walletModel);
180 transactionView.setModel(&walletModel);
182 // Send two transactions, and verify they are added to transaction list.
183 TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
184 QCOMPARE(transactionTableModel->rowCount({}), 105);
185 uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
186 uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
187 QCOMPARE(transactionTableModel->rowCount({}), 107);
188 QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
189 QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
191 // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
192 BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
193 BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
194 BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
195 BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
197 // Check current balance on OverviewPage
198 OverviewPage overviewPage(platformStyle.get());
199 overviewPage.setWalletModel(&walletModel);
200 QLabel* balanceLabel = overviewPage.findChild<QLabel*>("labelBalance");
201 QString balanceText = balanceLabel->text();
202 int unit = walletModel.getOptionsModel()->getDisplayUnit();
203 CAmount balance = walletModel.getBalance();
204 QString balanceComparison = BitcoinUnits::formatWithUnit(unit, balance, false, BitcoinUnits::separatorAlways);
205 QCOMPARE(balanceText, balanceComparison);
207 // Check Request Payment button
208 ReceiveCoinsDialog receiveCoinsDialog(platformStyle.get());
209 receiveCoinsDialog.setModel(&walletModel);
210 RecentRequestsTableModel* requestTableModel = walletModel.getRecentRequestsTableModel();
212 // Label input
213 QLineEdit* labelInput = receiveCoinsDialog.findChild<QLineEdit*>("reqLabel");
214 labelInput->setText("TEST_LABEL_1");
216 // Amount input
217 BitcoinAmountField* amountInput = receiveCoinsDialog.findChild<BitcoinAmountField*>("reqAmount");
218 amountInput->setValue(1);
220 // Message input
221 QLineEdit* messageInput = receiveCoinsDialog.findChild<QLineEdit*>("reqMessage");
222 messageInput->setText("TEST_MESSAGE_1");
223 int initialRowCount = requestTableModel->rowCount({});
224 QPushButton* requestPaymentButton = receiveCoinsDialog.findChild<QPushButton*>("receiveButton");
225 requestPaymentButton->click();
226 for (QWidget* widget : QApplication::topLevelWidgets()) {
227 if (widget->inherits("ReceiveRequestDialog")) {
228 ReceiveRequestDialog* receiveRequestDialog = qobject_cast<ReceiveRequestDialog*>(widget);
229 QTextEdit* rlist = receiveRequestDialog->QObject::findChild<QTextEdit*>("outUri");
230 QString paymentText = rlist->toPlainText();
231 QStringList paymentTextList = paymentText.split('\n');
232 QCOMPARE(paymentTextList.at(0), QString("Payment information"));
233 QVERIFY(paymentTextList.at(1).indexOf(QString("URI: bitcoin:")) != -1);
234 QVERIFY(paymentTextList.at(2).indexOf(QString("Address:")) != -1);
235 QCOMPARE(paymentTextList.at(3), QString("Amount: 0.00000001 ") + QString::fromStdString(CURRENCY_UNIT));
236 QCOMPARE(paymentTextList.at(4), QString("Label: TEST_LABEL_1"));
237 QCOMPARE(paymentTextList.at(5), QString("Message: TEST_MESSAGE_1"));
241 // Clear button
242 QPushButton* clearButton = receiveCoinsDialog.findChild<QPushButton*>("clearButton");
243 clearButton->click();
244 QCOMPARE(labelInput->text(), QString(""));
245 QCOMPARE(amountInput->value(), CAmount(0));
246 QCOMPARE(messageInput->text(), QString(""));
248 // Check addition to history
249 int currentRowCount = requestTableModel->rowCount({});
250 QCOMPARE(currentRowCount, initialRowCount+1);
252 // Check Remove button
253 QTableView* table = receiveCoinsDialog.findChild<QTableView*>("recentRequestsView");
254 table->selectRow(currentRowCount-1);
255 QPushButton* removeRequestButton = receiveCoinsDialog.findChild<QPushButton*>("removeRequestButton");
256 removeRequestButton->click();
257 QCOMPARE(requestTableModel->rowCount({}), currentRowCount-1);
259 bitdb.Flush(true);
260 bitdb.Reset();
265 void WalletTests::walletTests()
267 TestGUI();