Files
pay/testing/payment/TestPayment.cpp
tomFlowee 45ab9b23bb Wrap Wallet in shared_ptr
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.
2025-10-08 22:54:27 +02:00

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)