[test] Add getblockchaininfo functional test
[bitcoinplatinum.git] / src / qt / test / wallettests.cpp
blob5031d7651d8afa8eb53b767d5b8e144c0096f56e
1 #include "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"
17 #include <QAbstractButton>
18 #include <QAction>
19 #include <QApplication>
20 #include <QCheckBox>
21 #include <QPushButton>
22 #include <QTimer>
23 #include <QVBoxLayout>
25 namespace
27 //! Press "Ok" button in message box dialog.
28 void ConfirmMessage(QString* text = nullptr)
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();
38 delete callback;
39 }), SLOT(call()));
42 //! Press "Yes" or "Cancel" buttons in modal send confirmation dialog.
43 void ConfirmSend(QString* text = nullptr, bool cancel = false)
45 QTimer::singleShot(0, makeCallback([text, cancel](Callback* callback) {
46 for (QWidget* widget : QApplication::topLevelWidgets()) {
47 if (widget->inherits("SendConfirmationDialog")) {
48 SendConfirmationDialog* dialog = qobject_cast<SendConfirmationDialog*>(widget);
49 if (text) *text = dialog->text();
50 QAbstractButton* button = dialog->button(cancel ? QMessageBox::Cancel : QMessageBox::Yes);
51 button->setEnabled(true);
52 button->click();
55 delete callback;
56 }), SLOT(call()));
59 //! Send coins to address and return txid.
60 uint256 SendCoins(CWallet& wallet, SendCoinsDialog& sendCoinsDialog, const CTxDestination& address, CAmount amount, bool rbf)
62 QVBoxLayout* entries = sendCoinsDialog.findChild<QVBoxLayout*>("entries");
63 SendCoinsEntry* entry = qobject_cast<SendCoinsEntry*>(entries->itemAt(0)->widget());
64 entry->findChild<QValidatedLineEdit*>("payTo")->setText(QString::fromStdString(EncodeDestination(address)));
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);
70 uint256 txid;
71 boost::signals2::scoped_connection c(wallet.NotifyTransactionChanged.connect([&txid](CWallet*, const uint256& hash, ChangeType status) {
72 if (status == CT_NEW) txid = hash;
73 }));
74 ConfirmSend();
75 QMetaObject::invokeMethod(&sendCoinsDialog, "on_sendButton_clicked");
76 return txid;
79 //! Find index of txid in transaction list.
80 QModelIndex FindTx(const QAbstractItemModel& model, const uint256& txid)
82 QString hash = QString::fromStdString(txid.ToString());
83 int rows = model.rowCount({});
84 for (int row = 0; row < rows; ++row) {
85 QModelIndex index = model.index(row, 0, {});
86 if (model.data(index, TransactionTableModel::TxHashRole) == hash) {
87 return index;
90 return {};
93 //! Request context menu (call method that is public in qt5, but protected in qt4).
94 void RequestContextMenu(QWidget* widget)
96 class Qt4Hack : public QWidget
98 public:
99 using QWidget::customContextMenuRequested;
101 static_cast<Qt4Hack*>(widget)->customContextMenuRequested({});
104 //! Invoke bumpfee on txid and check results.
105 void BumpFee(TransactionView& view, const uint256& txid, bool expectDisabled, std::string expectError, bool cancel)
107 QTableView* table = view.findChild<QTableView*>("transactionView");
108 QModelIndex index = FindTx(*table->selectionModel()->model(), txid);
109 QVERIFY2(index.isValid(), "Could not find BumpFee txid");
111 // Select row in table, invoke context menu, and make sure bumpfee action is
112 // enabled or disabled as expected.
113 QAction* action = view.findChild<QAction*>("bumpFeeAction");
114 table->selectionModel()->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
115 action->setEnabled(expectDisabled);
116 RequestContextMenu(table);
117 QCOMPARE(action->isEnabled(), !expectDisabled);
119 action->setEnabled(true);
120 QString text;
121 if (expectError.empty()) {
122 ConfirmSend(&text, cancel);
123 } else {
124 ConfirmMessage(&text);
126 action->trigger();
127 QVERIFY(text.indexOf(QString::fromStdString(expectError)) != -1);
130 //! Simple qt wallet tests.
132 // Test widgets can be debugged interactively calling show() on them and
133 // manually running the event loop, e.g.:
135 // sendCoinsDialog.show();
136 // QEventLoop().exec();
138 // This also requires overriding the default minimal Qt platform:
140 // src/qt/test/test_bitcoin-qt -platform xcb # Linux
141 // src/qt/test/test_bitcoin-qt -platform windows # Windows
142 // src/qt/test/test_bitcoin-qt -platform cocoa # macOS
143 void TestSendCoins()
145 // Set up wallet and chain with 105 blocks (5 mature blocks for spending).
146 TestChain100Setup test;
147 for (int i = 0; i < 5; ++i) {
148 test.CreateAndProcessBlock({}, GetScriptForRawPubKey(test.coinbaseKey.GetPubKey()));
150 bitdb.MakeMock();
151 std::unique_ptr<CWalletDBWrapper> dbw(new CWalletDBWrapper(&bitdb, "wallet_test.dat"));
152 CWallet wallet(std::move(dbw));
153 bool firstRun;
154 wallet.LoadWallet(firstRun);
156 LOCK(wallet.cs_wallet);
157 wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
158 wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
160 wallet.ScanForWalletTransactions(chainActive.Genesis(), true);
161 wallet.SetBroadcastTransactions(true);
163 // Create widgets for sending coins and listing transactions.
164 std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other"));
165 SendCoinsDialog sendCoinsDialog(platformStyle.get());
166 TransactionView transactionView(platformStyle.get());
167 OptionsModel optionsModel;
168 WalletModel walletModel(platformStyle.get(), &wallet, &optionsModel);
169 sendCoinsDialog.setModel(&walletModel);
170 transactionView.setModel(&walletModel);
172 // Send two transactions, and verify they are added to transaction list.
173 TransactionTableModel* transactionTableModel = walletModel.getTransactionTableModel();
174 QCOMPARE(transactionTableModel->rowCount({}), 105);
175 uint256 txid1 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 5 * COIN, false /* rbf */);
176 uint256 txid2 = SendCoins(wallet, sendCoinsDialog, CKeyID(), 10 * COIN, true /* rbf */);
177 QCOMPARE(transactionTableModel->rowCount({}), 107);
178 QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
179 QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
181 // Call bumpfee. Test disabled, canceled, enabled, then failing cases.
182 BumpFee(transactionView, txid1, true /* expect disabled */, "not BIP 125 replaceable" /* expected error */, false /* cancel */);
183 BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, true /* cancel */);
184 BumpFee(transactionView, txid2, false /* expect disabled */, {} /* expected error */, false /* cancel */);
185 BumpFee(transactionView, txid2, true /* expect disabled */, "already bumped" /* expected error */, false /* cancel */);
187 bitdb.Flush(true);
188 bitdb.Reset();
193 void WalletTests::walletTests()
195 TestSendCoins();