45ab9b23bb
The Wallet object used to have a guarenteed lifetime longer than the App singleton, but then we started allowing people to delete their wallet (argh!). Also "external" modules, especially living outside of the main tree, would be much more stable if they can avoid using raw pointers for core concepts like the Wallet.
271 lines
9.4 KiB
C++
271 lines
9.4 KiB
C++
/*
|
|
* This file is part of the Flowee project
|
|
* Copyright (C) 2025 Tom Zander <tom@flowee.org>
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "TestPayment.h"
|
|
|
|
#include <Payment.h>
|
|
#include <PaymentDetailOutput_p.h>
|
|
#include <RepeatPaymentDetails.h>
|
|
#include <QStandardPaths>
|
|
#include <Wallet.h>
|
|
#include <qtest.h>
|
|
#include <qtestcase.h>
|
|
|
|
#include <primitives/script.h>
|
|
|
|
std::shared_ptr<Wallet> TestPayment::createWallet()
|
|
{
|
|
if (m_dir.isEmpty()) {
|
|
QString basedir = QStandardPaths::writableLocation(QStandardPaths::TempLocation);
|
|
m_dir = basedir + QString("/floweepay-%1/").arg(QCoreApplication::instance()->applicationPid());
|
|
}
|
|
|
|
return Wallet::createWallet(m_dir.toStdString(), 1111, "test");
|
|
}
|
|
|
|
void TestPayment::basic()
|
|
{
|
|
Streaming::ConstBuffer saveFile;
|
|
{
|
|
Payment payment;
|
|
payment.setPaymentAmount(1001000);
|
|
payment.setUserComment("my comment");
|
|
QCOMPARE(payment.paymentAmount(), 1001000);
|
|
payment.setFeePerByte(80);
|
|
payment.setFiatPrice(40000); // price per coin.
|
|
QCOMPARE(payment.feePerByte(), 80);
|
|
QCOMPARE(payment.paymentAmount(), 1001000);
|
|
QCOMPARE(payment.paymentAmountFiat(), 400);
|
|
QCOMPARE(payment.userComment(), "my comment");
|
|
|
|
auto pool = std::make_shared<Streaming::BufferPool>();
|
|
saveFile = payment.save(pool);
|
|
}
|
|
auto dummy = createWallet();
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
QCOMPARE(payment.feePerByte(), 80);
|
|
QCOMPARE(payment.paymentAmount(), 1001000);
|
|
QCOMPARE(payment.paymentAmountFiat(), 400);
|
|
QCOMPARE(payment.userComment(), "my comment");
|
|
}
|
|
}
|
|
|
|
void TestPayment::saveOutput()
|
|
{
|
|
auto pool = std::make_shared<Streaming::BufferPool>();
|
|
Streaming::ConstBuffer saveFile;
|
|
{
|
|
Payment payment;
|
|
payment.setFiatPrice(40000); // price per coin.
|
|
auto det = payment.paymentDetails();
|
|
QCOMPARE(det.size() , 1);
|
|
auto *out = qobject_cast<PaymentDetailOutput*>(det.at(0));
|
|
QVERIFY(out != nullptr);
|
|
out->setPaymentAmount(999011124);
|
|
out->setFiatFollows(true);
|
|
out->setAddress("hello");
|
|
|
|
saveFile = payment.save(pool);
|
|
}
|
|
auto dummy = createWallet();
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
auto det = payment.paymentDetails();
|
|
QCOMPARE(det.size() , 1);
|
|
auto *out = qobject_cast<PaymentDetailOutput*>(det.at(0));
|
|
QVERIFY(out != nullptr);
|
|
QCOMPARE(out->paymentAmount(), 999011124);
|
|
QCOMPARE(out->fiatFollows(), true);
|
|
QVERIFY(out->outputScript().isEmpty());
|
|
QCOMPARE(out->address(), "hello");
|
|
QCOMPARE(payment.repeatDetails(), nullptr);
|
|
|
|
const auto copy = out->paymentAmountFiat();
|
|
out->setFiatFollows(false);
|
|
out->setPaymentAmountFiat(copy);
|
|
saveFile = payment.save(pool);
|
|
}
|
|
|
|
pool->write("someScript");
|
|
Streaming::ConstBuffer outScript = pool->commit();
|
|
QCOMPARE(outScript.size(), 10);
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
auto det = payment.paymentDetails();
|
|
QCOMPARE(det.size() , 1);
|
|
auto *out = qobject_cast<PaymentDetailOutput*>(det.at(0));
|
|
QVERIFY(out != nullptr);
|
|
QCOMPARE(out->fiatFollows(), false);
|
|
QCOMPARE(out->paymentAmount(), 999010000); // some rounding.
|
|
QVERIFY(out->outputScript().isEmpty());
|
|
QCOMPARE(out->address(), "hello");
|
|
QCOMPARE(payment.repeatDetails(), nullptr);
|
|
|
|
out->setOutputScript(outScript);
|
|
QVERIFY(out->address().isEmpty());
|
|
saveFile = payment.save(pool);
|
|
}
|
|
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
auto det = payment.paymentDetails();
|
|
QCOMPARE(det.size() , 1);
|
|
auto *out = qobject_cast<PaymentDetailOutput*>(det.at(0));
|
|
QVERIFY(out != nullptr);
|
|
QCOMPARE(out->fiatFollows(), false);
|
|
QCOMPARE(out->paymentAmount(), 999010000);
|
|
QCOMPARE(out->outputScript(), outScript);
|
|
QVERIFY(out->address().isEmpty());
|
|
QCOMPARE(payment.repeatDetails(), nullptr);
|
|
}
|
|
}
|
|
|
|
void TestPayment::saveRepeat()
|
|
{
|
|
auto pool = std::make_shared<Streaming::BufferPool>();
|
|
Streaming::ConstBuffer saveFile;
|
|
{
|
|
Payment payment;
|
|
payment.setFiatPrice(40000); // price per coin.
|
|
QCOMPARE(payment.repeatDetails(), nullptr);
|
|
payment.makeRepeating();
|
|
auto *r = payment.repeatDetails();
|
|
QVERIFY(r != nullptr);
|
|
// first an empty one.
|
|
saveFile = payment.save(pool);
|
|
}
|
|
auto dummy = createWallet();
|
|
{
|
|
Payment payment;
|
|
QCOMPARE(payment.repeatDetails(), nullptr);
|
|
payment.makeRepeating();
|
|
auto *r = payment.repeatDetails();
|
|
QVERIFY(r != nullptr);
|
|
|
|
r->addRepeatDayOfMonth(30, 1, 4);
|
|
r->addRepeatDayOfMonth(7);
|
|
r->addRepeatDayOfMonth(9, 2);
|
|
saveFile = payment.save(pool);
|
|
}
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
auto *r = payment.repeatDetails();
|
|
QVERIFY(r != nullptr);
|
|
QVERIFY(!r->sunset().isValid());
|
|
auto confs = r->repeatConfig();
|
|
QCOMPARE(confs.size(), 3);
|
|
auto conf = confs.at(0); // they get sorted on insert.
|
|
QCOMPARE(conf.dayOfMonth, 7);
|
|
QCOMPARE(conf.dayOfWeek, -1);
|
|
QCOMPARE(conf.weekInterval, -1);
|
|
QCOMPARE(conf.monthInterval, -1);
|
|
conf = confs.at(1);
|
|
QCOMPARE(conf.dayOfMonth, 9);
|
|
QCOMPARE(conf.dayOfWeek, -1);
|
|
QCOMPARE(conf.weekInterval, 2);
|
|
QCOMPARE(conf.monthInterval, -1);
|
|
conf = confs.at(2);
|
|
QCOMPARE(conf.dayOfMonth, 30);
|
|
QCOMPARE(conf.dayOfWeek, -1);
|
|
QCOMPARE(conf.weekInterval, 1);
|
|
QCOMPARE(conf.monthInterval, 4);
|
|
|
|
r->setRepeatConfig(QVector<RepeatPaymentDetails::Config>()); // clear
|
|
r->addRepeatRelative(1, 4);
|
|
r->setSunset(QDate(2030, 10, 30));
|
|
confs = r->repeatConfig();
|
|
confs[0].baseDate = QDateTime(QDate(2025, 05, 3), QTime(14,00));
|
|
r->setRepeatConfig(confs);
|
|
|
|
QCOMPARE(r->currencyLocale(), "");
|
|
QCOMPARE(r->enabled(), true);
|
|
QCOMPARE(r->autoApprove(), false);
|
|
r->setCurrencyLocale("en_FL");
|
|
r->setEnabled(false);
|
|
r->setAutoApprove(true);
|
|
|
|
saveFile = payment.save(pool);
|
|
}
|
|
{
|
|
Payment payment(saveFile, dummy);
|
|
auto *r = payment.repeatDetails();
|
|
QVERIFY(r != nullptr);
|
|
QCOMPARE(r->sunset(), QDate(2030, 10, 30));
|
|
auto confs = r->repeatConfig();
|
|
QCOMPARE(confs.size(), 1);
|
|
auto conf = confs.at(0);
|
|
QCOMPARE(conf.dayOfMonth, -1);
|
|
QCOMPARE(conf.dayOfWeek, 1);
|
|
QCOMPARE(conf.weekInterval, 4);
|
|
QCOMPARE(conf.monthInterval, -1);
|
|
QCOMPARE(conf.baseDate, QDateTime(QDate(2025, 05, 3), QTime(14,00)));
|
|
QCOMPARE(r->currencyLocale(), "en_FL");
|
|
QCOMPARE(r->enabled(), false);
|
|
QCOMPARE(r->autoApprove(), true);
|
|
// saveFile = payment.save(pool);
|
|
}
|
|
}
|
|
|
|
void TestPayment::next()
|
|
{
|
|
const QTime time(13, 34);
|
|
RepeatPaymentDetails::Config config;
|
|
config.dayOfMonth = 13;
|
|
config.baseDate = QDateTime(QDate(2025, 3, 20), time);
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 4, 13), time));
|
|
config.monthInterval = 3;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 6, 13), time));
|
|
config.monthInterval = -1;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 4, 13), time));
|
|
|
|
config.baseDate = QDateTime(QDate(2025, 1, 30), time);
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 2, 13), time));
|
|
config.baseDate = QDateTime(QDate(2025, 2, 13), time);
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 3, 13), time));
|
|
config.monthInterval = 3;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 5, 13), time));
|
|
|
|
// impossible date handling
|
|
config.baseDate = QDateTime(QDate(2025, 2, 4), time);
|
|
config.dayOfMonth = 31;
|
|
config.monthInterval = 3;
|
|
// As feb 31 is impossible, I expect it to be May due to the 3 month interval
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 5, 31), time));
|
|
config.monthInterval = 12; // an impossible repeat
|
|
QVERIFY(!config.next().isValid());
|
|
|
|
|
|
config = RepeatPaymentDetails::Config();
|
|
config.dayOfWeek = 2; // tuesday
|
|
config.baseDate = QDateTime(QDate(2025, 3, 20), time);
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 3, 25), time));
|
|
config.baseDate = QDateTime(QDate(2025, 3, 25), time);
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 4, 1), time));
|
|
config.weekInterval = 2;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 4, 8), time));
|
|
config.weekInterval = 3;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 4, 15), time));
|
|
config.weekInterval = 7;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 5, 13), time));
|
|
config.weekInterval = 0;
|
|
config.monthInterval = 2;
|
|
QCOMPARE(config.next(), QDateTime(QDate(2025, 5, 27), time));
|
|
}
|
|
|
|
QTEST_MAIN(TestPayment)
|