summaryrefslogtreecommitdiffstats
path: root/kmymoney2/mymoney/mymoneyforecasttest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmymoney2/mymoney/mymoneyforecasttest.cpp')
-rw-r--r--kmymoney2/mymoney/mymoneyforecasttest.cpp977
1 files changed, 977 insertions, 0 deletions
diff --git a/kmymoney2/mymoney/mymoneyforecasttest.cpp b/kmymoney2/mymoney/mymoneyforecasttest.cpp
new file mode 100644
index 0000000..dbe96ac
--- /dev/null
+++ b/kmymoney2/mymoney/mymoneyforecasttest.cpp
@@ -0,0 +1,977 @@
+/***************************************************************************
+ mymoneyforecasttest.cpp
+ -------------------
+ copyright : (C) 2007 by Alvaro Soliverez
+ email : asoliverez@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * 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 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include "mymoneyforecasttest.h"
+
+#include <iostream>
+#include <qvaluelist.h>
+
+#include "mymoneybudget.h"
+
+#include <kmymoney/mymoneyexception.h>
+
+#include "../kmymoneyglobalsettings.h"
+#include "../mymoney/storage/mymoneystoragedump.h"
+#include "../mymoney/storage/mymoneystoragexml.h"
+#include "../reports/reportstestcommon.h"
+
+
+using namespace test;
+
+MyMoneyForecastTest::MyMoneyForecastTest()
+{
+ this->moT1 = MyMoneyMoney(57,1);
+ this->moT2 = MyMoneyMoney(63,1);
+ this->moT3 = MyMoneyMoney(84,1);
+ this->moT4 = MyMoneyMoney(62,1);
+ this->moT5 = MyMoneyMoney(104,1);
+}
+
+
+void MyMoneyForecastTest::setUp () {
+
+ //all this has been taken from pivottabletest.cpp, by Thomas Baumgart and Ace Jones
+
+ storage = new MyMoneySeqAccessMgr;
+ file = MyMoneyFile::instance();
+ file->attachStorage(storage);
+
+ MyMoneyFileTransaction ft;
+ file->addCurrency(MyMoneySecurity("CAD", "Canadian Dollar", "C$"));
+ file->addCurrency(MyMoneySecurity("USD", "US Dollar", "$"));
+ file->addCurrency(MyMoneySecurity("JPY", "Japanese Yen", QChar(0x00A5), 100, 1));
+ file->addCurrency(MyMoneySecurity("GBP", "British Pound", "#"));
+ file->setBaseCurrency(file->currency("USD"));
+
+ MyMoneyPayee payeeTest("Test Payee");
+ file->addPayee(payeeTest);
+ MyMoneyPayee payeeTest2("Alvaro Soliverez");
+ file->addPayee(payeeTest2);
+
+ acAsset = (MyMoneyFile::instance()->asset().id());
+ acLiability = (MyMoneyFile::instance()->liability().id());
+ acExpense = (MyMoneyFile::instance()->expense().id());
+ acIncome = (MyMoneyFile::instance()->income().id());
+ acChecking = makeAccount(QString("Checking Account"),MyMoneyAccount::Checkings,moCheckingOpen,QDate(2004,5,15),acAsset, "USD");
+ acCredit = makeAccount(QString("Credit Card"),MyMoneyAccount::CreditCard,moCreditOpen,QDate(2004,7,15),acLiability, "USD");
+ acSolo = makeAccount(QString("Solo"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acParent = makeAccount(QString("Parent"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acChild = makeAccount(QString("Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent, "USD");
+ acForeign = makeAccount(QString("Foreign"),MyMoneyAccount::Expense,0,QDate(2004,1,11),acExpense, "USD");
+ acInvestment = makeAccount("Investment",MyMoneyAccount::Investment,moZero,QDate(2004,1,1),acAsset, "USD");
+
+ acSecondChild = makeAccount(QString("Second Child"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acParent, "USD");
+ acGrandChild1 = makeAccount(QString("Grand Child 1"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild, "USD");
+ acGrandChild2 = makeAccount(QString("Grand Child 2"),MyMoneyAccount::Expense,0,QDate(2004,2,11),acChild, "USD");
+
+ //this account added to have an account to test opening date calculations
+ acCash = makeAccount(QString("Cash"),MyMoneyAccount::Cash,moCreditOpen,QDate::currentDate().addDays(-2),acAsset, "USD");
+
+
+ MyMoneyInstitution i("Bank of the World","","","","","","");
+ file->addInstitution(i);
+ inBank = i.id();
+ ft.commit();
+
+}
+
+void MyMoneyForecastTest::tearDown () {
+ file->detachStorage(storage);
+ delete storage;
+}
+
+void MyMoneyForecastTest::testEmptyConstructor() {
+ MyMoneyForecast a;
+ MyMoneyAccount b;
+
+ int f = a.forecastBalance(b, QDate::currentDate());
+
+ CPPUNIT_ASSERT(f == 0);
+ CPPUNIT_ASSERT(!a.isForecastAccount(b));
+ CPPUNIT_ASSERT(a.forecastBalance(b, QDate::currentDate()) == MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(b) == -1);
+ CPPUNIT_ASSERT(a.daysToZeroBalance(b) == -2);
+ CPPUNIT_ASSERT(a.forecastDays() == KMyMoneyGlobalSettings::forecastDays());
+ CPPUNIT_ASSERT(a.accountsCycle() == KMyMoneyGlobalSettings::forecastAccountCycle());
+ CPPUNIT_ASSERT(a.forecastCycles() == KMyMoneyGlobalSettings::forecastCycles());
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-KMyMoneyGlobalSettings::forecastCycles()*KMyMoneyGlobalSettings::forecastAccountCycle()));
+ CPPUNIT_ASSERT(a.historyEndDate() == QDate::currentDate().addDays(-1));
+ CPPUNIT_ASSERT(a.historyDays() == KMyMoneyGlobalSettings::forecastAccountCycle() * KMyMoneyGlobalSettings::forecastCycles());
+}
+
+
+void MyMoneyForecastTest::testDoForecastInit() {
+ MyMoneyForecast a;
+
+ a.doForecast();
+ /*
+ //check the illegal argument validation
+ try {
+ KMyMoneyGlobalSettings::setForecastDays(-10);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e)
+ {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastAccountCycle(-20);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastCycles(-10);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ try {
+ KMyMoneyGlobalSettings::setForecastAccountCycle(0);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+ try {
+ KMyMoneyGlobalSettings::setForecastDays(0);
+ KMyMoneyGlobalSettings::setForecastCycles(0);
+ KMyMoneyGlobalSettings::setForecastAccountCycle(0);
+ a.doForecast();
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_ASSERT("Unexpected exception");
+ }*/
+}
+
+//test that it forecasts correctly with transactions in the period of forecast
+void MyMoneyForecastTest::testDoForecast() {
+ //set up environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //test empty forecast
+ a.doForecast(); //this is just to check nothing goes wrong if forecast is run agains an empty template
+
+ //setup some transactions
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(0); //moving average
+ a.doForecast();
+
+ //checking didn't have balance variations, so the forecast should be equal to the current balance
+ MyMoneyMoney b_checking = file->balance(a_checking.id(), QDate::currentDate());
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(1))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(2))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(3))==b_checking);
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate())==b_checking);
+ //credit had a variation so the forecast should be different for each day
+ MyMoneyMoney b_credit = file->balance(a_credit.id(), QDate::currentDate());
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(moT2-moT1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2)) == (b_credit+((moT2-moT1)*2)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3)) == b_credit+((moT2-moT1)*3));
+
+ a.setHistoryMethod(1); //weighted moving average
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(moT2-moT1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2)) == (b_credit+((moT2-moT1)*2)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3)) == b_credit+((moT2-moT1)*3));
+
+ //insert transactions outside the forecast period. The calculation should be the same.
+ TransactionHelper t4( QDate::currentDate().addDays(-2), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+ TransactionHelper t5( QDate::currentDate().addDays(-10), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+ TransactionHelper t6( QDate::currentDate().addDays(-3), MyMoneySplit::ActionDeposit, -moT2, acCredit, acParent );
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(0); //moving average
+ a.doForecast();
+ //check forecast
+ b_credit = file->balance(a_credit.id(), QDate::currentDate());
+ MyMoneyMoney b_credit_1_exp = (b_credit+((moT2-moT1)));
+ MyMoneyMoney b_credit_2 = a.forecastBalance(a_credit, QDate::currentDate().addDays(2));
+ MyMoneyMoney b_credit_2_exp = (b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate())==file->balance(a_credit.id(), QDate::currentDate()));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1))==b_credit+(moT2-moT1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2))==b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3))==b_credit+((moT2-moT1)*3));
+
+ //test weighted moving average
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.setHistoryMethod(1);
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, 0) == b_credit);
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1)) == (b_credit+(((moT2-moT1)*3+moT2*2+moT2)/MyMoneyMoney(6,1))));
+
+}
+
+void MyMoneyForecastTest::testGetForecastAccountList()
+{
+ MyMoneyForecast a;
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_parent = file->account(acParent);
+ QValueList<MyMoneyAccount> b;
+
+ b = a.forecastAccountList();
+ //check that it contains asset account, but not expense accounts
+ CPPUNIT_ASSERT(b.contains(a_checking));
+ CPPUNIT_ASSERT(!b.contains(a_parent));
+
+}
+
+void MyMoneyForecastTest::testCalculateAccountTrend()
+{
+ //set up environment
+ TransactionHelper t1( QDate::currentDate().addDays(-3), MyMoneySplit::ActionDeposit, -moT2, acChecking, acSolo );
+ MyMoneyAccount a_checking = file->account(acChecking);
+
+ //test invalid arguments
+
+ try {
+ MyMoneyForecast::calculateAccountTrend(a_checking, 0);
+ }
+ catch (MyMoneyException *e) {
+ CPPUNIT_ASSERT(e->what().compare("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0") == 0);
+ delete e;
+ }
+ try {
+ MyMoneyForecast::calculateAccountTrend(a_checking, -10);
+ }
+ catch (MyMoneyException *e) {
+ CPPUNIT_ASSERT(e->what().compare("Illegal arguments when calling calculateAccountTrend. trendDays must be higher than 0") == 0);
+ delete e;
+ }
+
+ //test that it calculates correctly
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_checking ,3) == moT2/MyMoneyMoney(3,1));
+
+ //test that it works for all kind of accounts
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyMoney soloTrend = MyMoneyForecast::calculateAccountTrend(a_solo,3);
+ MyMoneyMoney soloTrendExp = -moT2/MyMoneyMoney(3,1);
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_solo,3) == -moT2/MyMoneyMoney(3,1));
+
+ //test that it does not take into account the transactions of the opening date of the account
+ MyMoneyAccount a_cash = file->account(acCash);
+ TransactionHelper t2( QDate::currentDate().addDays(-2), MyMoneySplit::ActionDeposit, moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, moT1, acCash, acParent );
+ CPPUNIT_ASSERT(MyMoneyForecast::calculateAccountTrend(a_cash,3) == -moT1);
+
+}
+
+void MyMoneyForecastTest::testGetForecastBalance()
+{
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setHistoryMethod(0);
+ a.doForecast();
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //test invalid arguments
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(-1))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(-10))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, -1)==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, -100)==MyMoneyMoney(0,1));
+
+ //test a date outside the forecast days
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(4))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, 4)==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, QDate::currentDate().addDays(10))==MyMoneyMoney(0,1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_checking, 10)==MyMoneyMoney(0,1));
+
+ //test it returns valid results
+ MyMoneyMoney b_credit = file->balance(a_credit.id(), QDate::currentDate());
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate())==file->balance(a_credit.id(), QDate::currentDate()));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(1))==b_credit+(moT2-moT1));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(2))==b_credit+((moT2-moT1)*2));
+ CPPUNIT_ASSERT(a.forecastBalance(a_credit, QDate::currentDate().addDays(3))==b_credit+((moT2-moT1)*3));
+}
+
+void MyMoneyForecastTest::testIsForecastAccount()
+{
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyAccount a_investment = file->account(acInvestment);
+
+ //test an invalid account
+ CPPUNIT_ASSERT(a.isForecastAccount(a_solo)==false);
+ CPPUNIT_ASSERT(a.isForecastAccount(a_investment)==true);
+
+ //test a valid account
+ CPPUNIT_ASSERT(a.isForecastAccount(a_checking)==true);
+
+}
+
+void MyMoneyForecastTest::testDoFutureScheduledForecast()
+{
+ //set up future transactions
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_cash = file->account(acCash);
+ TransactionHelper t1( QDate::currentDate().addDays(1), MyMoneySplit::ActionDeposit, -moT1, acCash, acParent );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionDeposit, -moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(3), MyMoneySplit::ActionDeposit, -moT3, acCash, acParent );
+ TransactionHelper t4( QDate::currentDate().addDays(10), MyMoneySplit::ActionDeposit, -moT4, acCash, acParent );
+
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.doForecast();
+
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+
+ //test valid results
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash+moT1);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash+moT1+moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(3))==b_cash+moT1+moT2+moT3);
+}
+
+void MyMoneyForecastTest::testScheduleForecast()
+{
+ //set up schedule environment for testing
+ MyMoneyAccount a_cash = file->account(acCash);
+ MyMoneyAccount a_parent = file->account(acParent);
+
+ MyMoneyFileTransaction ft;
+ MyMoneySchedule sch( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(1),
+ QDate(),
+ true,
+ true);
+
+ MyMoneyTransaction t;
+ t.setPostDate(QDate::currentDate().addDays(1));
+ t.setEntryDate(QDate::currentDate().addDays(1));
+ //t.setId("T000000000000000001");
+ t.setBankID("BID");
+ t.setMemo("Wohnung:Miete");
+ t.setCommodity("USD");
+ t.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(moT2);
+ s.setValue(moT2);
+ s.setAccountId(a_parent.id());
+ s.setBankID("SPID1");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t.addSplit(s);
+
+ s.setPayeeId("P000001");
+ s.setShares(-moT2);
+ s.setValue(-moT2);
+ s.setAccountId(a_cash.id());
+ s.setBankID("SPID2");
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ t.addSplit(s);
+
+ sch.setTransaction(t);
+
+ file->addSchedule(sch);
+ ft.commit();
+
+ MyMoneyFileTransaction ft3;
+ MyMoneySchedule sch3( "A Name1",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(5),
+ QDate(),
+ true,
+ true);
+
+ //sch.setLastPayment(QDate::currentDate());
+ //sch.recordPayment(QDate::currentDate().addDays(1));
+ //sch.setId("SCH0001");
+
+ MyMoneyTransaction t3;
+ t3.setPostDate(QDate::currentDate().addDays(5));
+ t3.setEntryDate(QDate::currentDate().addDays(5));
+ //t.setId("T000000000000000001");
+ t3.setBankID("BID");
+ t3.setMemo("Wohnung:Miete");
+ t3.setCommodity("USD");
+ t3.setValue("key", "value");
+
+ MyMoneySplit s3;
+ s3.setPayeeId("P000001");
+ s3.setShares(moT2);
+ s3.setValue(moT2);
+ s3.setAccountId(a_parent.id());
+ s3.setBankID("SPID1");
+ s3.setReconcileFlag(MyMoneySplit::Reconciled);
+ t3.addSplit(s3);
+
+ s3.setPayeeId("P000001");
+ s3.setShares(-moT2);
+ s3.setValue(-moT2);
+ s3.setAccountId(a_cash.id());
+ s3.setBankID("SPID2");
+ s3.setReconcileFlag(MyMoneySplit::Cleared);
+ s3.clearId();
+ t3.addSplit(s3);
+
+ sch3.setTransaction(t3);
+
+ file->addSchedule(sch3);
+ ft3.commit();
+
+
+ MyMoneyFileTransaction ft2;
+ MyMoneySchedule sch2( "A Name2",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_WEEKLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate().addDays(2),
+ QDate(),
+ true,
+ true);
+
+ //sch.setLastPayment(QDate::currentDate());
+ //sch.recordPayment(QDate::currentDate().addDays(1));
+ //sch.setId("SCH0001");
+
+ MyMoneyTransaction t2;
+ t2.setPostDate(QDate::currentDate().addDays(2));
+ t2.setEntryDate(QDate::currentDate().addDays(2));
+ //t.setId("T000000000000000001");
+ t2.setBankID("BID");
+ t2.setMemo("Wohnung:Miete");
+ t2.setCommodity("USD");
+ t2.setValue("key", "value");
+
+ MyMoneySplit s2;
+ s2.setPayeeId("P000001");
+ s2.setShares(moT1);
+ s2.setValue(moT1);
+ s2.setAccountId(a_parent.id());
+ s2.setBankID("SPID1");
+ s2.setReconcileFlag(MyMoneySplit::Reconciled);
+ t2.addSplit(s2);
+
+ s2.setPayeeId("P000001");
+ s2.setShares(-moT1);
+ s2.setValue(-moT1);
+ s2.setAccountId(a_cash.id());
+ s2.setBankID("SPID2");
+ s2.setReconcileFlag(MyMoneySplit::Cleared);
+ s2.clearId();
+ t2.addSplit(s2);
+
+ sch2.setTransaction(t2);
+
+ file->addSchedule(sch2);
+
+ ft2.commit();
+
+ //run forecast
+ MyMoneyForecast a;
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.doForecast();
+
+ //check result for single schedule
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+ MyMoneyMoney b_cash1 = a.forecastBalance(a_cash, QDate::currentDate().addDays(1));
+
+ //test valid results
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash-moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash-moT2-moT1);
+}
+
+
+void MyMoneyForecastTest::testDaysToMinimumBalance()
+{
+ //setup environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_cash = file->account(acCash);
+ MyMoneyAccount a_credit = file->account(acCredit);
+ MyMoneyAccount a_parent = file->account(acParent);
+ a_cash.setValue("minBalanceAbsolute", "50");
+ a_credit.setValue("minBalanceAbsolute", "50");
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -moT1, acCash, acParent );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionDeposit, moT2, acCash, acParent );
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, -moT1, acCredit, acParent );
+ TransactionHelper t4( QDate::currentDate().addDays(4), MyMoneySplit::ActionWithdrawal, moT5, acCredit, acParent );
+
+ a.setForecastMethod(0);
+ a.setForecastDays(3);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ //test invalid arguments
+ MyMoneyAccount nullAcc;
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(nullAcc) == -1);
+
+ //test when not a forecast account
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_parent) == -1);
+
+ //test it warns when inside the forecast period
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_cash) == 2);
+
+ //test it does not warn when it will be outside of the forecast period
+ CPPUNIT_ASSERT(a.daysToMinimumBalance(a_credit) == -1);
+}
+void MyMoneyForecastTest::testDaysToZeroBalance()
+{
+ //set up environment
+ MyMoneyAccount a_Solo = file->account(acSolo);
+ MyMoneyAccount a_Cash = file->account(acCash);
+ MyMoneyAccount a_Credit = file->account(acCredit);
+
+ //MyMoneyFileTransaction ft;
+ TransactionHelper t1( QDate::currentDate().addDays(2), MyMoneySplit::ActionWithdrawal, -moT1, acChecking, acSolo );
+ TransactionHelper t2( QDate::currentDate().addDays(2), MyMoneySplit::ActionTransfer, (moT5), acCash, acCredit );
+ TransactionHelper t3( QDate::currentDate().addDays(2), MyMoneySplit::ActionWithdrawal, (moT5*100), acCredit, acParent );
+ //ft.commit();
+
+ MyMoneyForecast a;
+ a.setForecastMethod(0);
+ a.setForecastDays(30);
+ a.setAccountsCycle(1);
+ a.setForecastCycles(3);
+ a.doForecast();
+
+ //test invalid arguments
+ MyMoneyAccount nullAcc;
+ try {
+ a.daysToZeroBalance(nullAcc);
+ }
+ catch (MyMoneyException *e) {
+ delete e;
+ CPPUNIT_FAIL("Unexpected exception");
+ }
+
+ //test when not a forecast account
+ MyMoneyAccount a_solo = file->account(acSolo);
+ int iSolo = a.daysToZeroBalance(a_Solo);
+
+ CPPUNIT_ASSERT(iSolo == -2);
+
+ //test it warns when inside the forecast period
+
+ MyMoneyMoney fCash = a.forecastBalance(a_Cash, QDate::currentDate().addDays(2));
+
+ CPPUNIT_ASSERT(a.daysToZeroBalance(a_Cash) == 2);
+
+ //test it does not warn when it will be outside of the forecast period
+
+}
+
+void MyMoneyForecastTest::testSkipOpeningDate()
+{
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(1);
+ a.setHistoryMethod(0);
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test it has no variation because it skipped the variation of the opening date
+ MyMoneyMoney b_cash = file->balance(a_cash.id(), QDate::currentDate());
+ CPPUNIT_ASSERT(a.skipOpeningDate() == true);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate())==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(1))==b_cash);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(2))==b_cash-moT2);
+ CPPUNIT_ASSERT(a.forecastBalance(a_cash, QDate::currentDate().addDays(3))==b_cash-moT2);
+}
+
+void MyMoneyForecastTest::testAccountMinimumBalanceDateList() {
+
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(6);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(3);
+ a.setHistoryMethod(0);
+ a.setBeginForecastDay(QDate::currentDate().addDays(1).day());
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ QValueList<QDate> dateList;
+ dateList = a.accountMinimumBalanceDateList(a_cash);
+
+ QValueList<QDate>::iterator it = dateList.begin();
+
+ QDate minDate = *it;
+
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(2));
+ it++;
+ minDate = *it;
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(4));
+ it++;
+ minDate = *it;
+ CPPUNIT_ASSERT(minDate==QDate::currentDate().addDays(6));
+
+}
+
+void MyMoneyForecastTest::testAccountMaximumBalanceDateList() {
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(6);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(3);
+ a.setHistoryMethod(0);
+ a.setBeginForecastDay(QDate::currentDate().addDays(1).day());
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ QValueList<QDate> dateList;
+ dateList = a.accountMaximumBalanceDateList(a_cash);
+
+ QValueList<QDate>::iterator it = dateList.begin();
+
+ QDate maxDate = *it;
+
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(1));
+ it++;
+ maxDate = *it;
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(3));
+ it++;
+ maxDate = *it;
+ CPPUNIT_ASSERT(maxDate==QDate::currentDate().addDays(5));
+
+
+}
+
+void MyMoneyForecastTest::testAccountAverageBalance() {
+ //set up environment
+ MyMoneyForecast a;
+
+ TransactionHelper t1( QDate::currentDate().addDays(-2), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acSolo);
+
+ a.setForecastMethod(1);
+ a.setForecastDays(3);
+ a.setAccountsCycle(2);
+ a.setForecastCycles(1);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ //test
+ MyMoneyMoney b_cash1 = a.forecastBalance(a_cash, QDate::currentDate().addDays(1));
+ MyMoneyMoney b_cash2 = a.forecastBalance(a_cash, QDate::currentDate().addDays(2));
+ MyMoneyMoney b_cash3 = a.forecastBalance(a_cash, QDate::currentDate().addDays(3));
+
+ MyMoneyMoney average = (b_cash1 + b_cash2 +b_cash3)/MyMoneyMoney(3,1);
+
+
+ CPPUNIT_ASSERT(a.accountAverageBalance(a_cash)==average);
+}
+
+void MyMoneyForecastTest::testBeginForecastDate() {
+ //set up environment
+ MyMoneyForecast a;
+ QDate beginDate;
+ int beginDay;
+
+ a.setForecastMethod(1);
+ a.setForecastDays(90);
+ a.setAccountsCycle(14);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ //test when using old method without begin day
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+
+ //setup begin to last day of month
+ a.setBeginForecastDay(31);
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ //test
+ if(QDate::currentDate().day() < beginDay)
+ {
+ if(QDate::currentDate().daysInMonth() < beginDay)
+ beginDay = QDate::currentDate().daysInMonth();
+
+ beginDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), beginDay);
+
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ }
+
+ //setup begin day to same date
+ a.setBeginForecastDay(QDate::currentDate().day());
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+
+ //setup to first day of month with small interval
+ a.setBeginForecastDay(1);
+ a.setAccountsCycle(1);
+ beginDay = a.beginForecastDay();
+ a.doForecast();
+
+ //test
+ if(QDate::currentDate() == a.beginForecastDate()) {
+ CPPUNIT_ASSERT(QDate::currentDate() == a.beginForecastDate());
+ } else {
+ beginDay = ((((QDate::currentDate().day() - beginDay)/a.accountsCycle()) + 1) * a.accountsCycle()) + beginDay;
+ if(beginDay > QDate::currentDate().daysInMonth())
+ beginDay = QDate::currentDate().daysInMonth();
+ beginDate = QDate(QDate::currentDate().year(), QDate::currentDate().month(), beginDay);
+ if(QDate::currentDate().day() == QDate::currentDate().daysInMonth() ) {
+ std::cout << std::endl << "testBeginForecastDate(): test of first day of month with small interval skipped because it is the last day of month" << std::endl;
+ } else {
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ }
+ }
+
+ //setup to test when current date plus cycle equals begin day
+ a.setAccountsCycle(14);
+ beginDay = QDate::currentDate().addDays(14).day();
+ a.setBeginForecastDay(beginDay);
+ beginDate = QDate::currentDate().addDays(14);
+ a.doForecast();
+
+ //test
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+
+ //setup to test when the begin day will be next month
+ a.setBeginForecastDay(1);
+ a.setAccountsCycle(40);
+ a.doForecast();
+
+ beginDate = QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1);
+
+ //test
+ if(QDate::currentDate().day() > 1) {
+ CPPUNIT_ASSERT(beginDate == a.beginForecastDate());
+ } else {
+ //test is not valid if today is 1st of month
+ std::cout << std::endl << "testBeginForecastDate(): test of first day of month skipped because current day is 1st of month" << std::endl;
+ }
+}
+
+ void MyMoneyForecastTest::testHistoryDays(void)
+{
+ MyMoneyForecast a;
+
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-a.forecastCycles()*a.accountsCycle()) );
+ CPPUNIT_ASSERT(a.historyEndDate() == QDate::currentDate().addDays(-1) );
+ CPPUNIT_ASSERT(a.historyDays() == a.forecastCycles()*a.accountsCycle());
+
+ a.setForecastMethod(1);
+ a.setForecastDays(90);
+ a.setAccountsCycle(14);
+ a.setForecastCycles(3);
+ a.setBeginForecastDay(0);
+ a.doForecast();
+
+ CPPUNIT_ASSERT(a.historyStartDate() == QDate::currentDate().addDays(-14*3) );
+ CPPUNIT_ASSERT(a.historyDays() == (14*3));
+ CPPUNIT_ASSERT(a.historyEndDate() == (QDate::currentDate().addDays(-1)) );
+}
+
+void MyMoneyForecastTest::testCreateBudget()
+{
+ //set up environment
+ MyMoneyForecast a;
+ MyMoneyForecast b;
+ MyMoneyBudget budget;
+
+ TransactionHelper t1( QDate(2005, 1, 3), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t2( QDate(2005, 1, 15), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acParent);
+ TransactionHelper t3( QDate(2005, 1, 30), MyMoneySplit::ActionWithdrawal, this->moT3, acCash, acSolo);
+ TransactionHelper t4( QDate(2006, 1, 25), MyMoneySplit::ActionWithdrawal, this->moT4, acCash, acParent);
+ TransactionHelper t5( QDate(2005, 4, 3), MyMoneySplit::ActionWithdrawal, this->moT1, acCash, acSolo);
+ TransactionHelper t6( QDate(2006, 5, 15), MyMoneySplit::ActionWithdrawal, this->moT2, acCash, acParent);
+ TransactionHelper t7( QDate(2005, 8, 3), MyMoneySplit::ActionWithdrawal, this->moT3, acCash, acSolo);
+ TransactionHelper t8( QDate(2006, 9, 15), MyMoneySplit::ActionWithdrawal, this->moT4, acCash, acParent);
+
+ a.setHistoryMethod(0);
+ a.setForecastMethod(1);
+ a.createBudget(budget, QDate(2005, 1, 1), QDate(2006, 12, 31), QDate(2007, 1, 1), QDate(2007, 12, 31), true);
+
+ //test
+ MyMoneyAccount a_solo = file->account(acSolo);
+ MyMoneyAccount a_parent = file->account(acParent);
+
+ //test it has no variation because it skipped the variation of the opening date
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 1, 1)) == ((moT1+moT3)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 1, 1)) == ((moT2+moT4)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 4, 1)) == ((moT1)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 5, 1)) == ((moT2)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_solo, QDate(2007, 8, 1)) == ((moT3)/MyMoneyMoney(2, 1)));
+ CPPUNIT_ASSERT(a.forecastBalance(a_parent, QDate(2007, 9, 1)) == ((moT4)/MyMoneyMoney(2, 1)));
+ //test the budget object returned by the method
+ CPPUNIT_ASSERT(budget.account(a_parent.id()).period(QDate(2007, 9, 1)).amount() == ((moT4)/MyMoneyMoney(2, 1)));
+
+ //setup test for a length lower than a year
+ b.setForecastMethod(1);
+ b.setHistoryMethod(0);
+ b.createBudget(budget, QDate(2005, 1, 1), QDate(2005, 6, 30), QDate(2007, 1, 1), QDate(2007, 6, 30), true);
+
+ //test
+ CPPUNIT_ASSERT(b.forecastBalance(a_solo, QDate(2007, 1, 1)) == (moT1+moT3));
+ CPPUNIT_ASSERT(b.forecastBalance(a_parent, QDate(2007, 1, 1)) == (moT2));
+ CPPUNIT_ASSERT(b.forecastBalance(a_solo, QDate(2007, 4, 1)) == (moT1));
+ CPPUNIT_ASSERT(b.forecastBalance(a_parent, QDate(2007, 5, 1)) == (MyMoneyMoney(0, 1)));
+
+ //set up schedule environment for testing
+ MyMoneyAccount a_cash = file->account(acCash);
+
+ MyMoneyFileTransaction ft;
+ MyMoneySchedule sch( "A Name",
+ MyMoneySchedule::TYPE_BILL,
+ MyMoneySchedule::OCCUR_MONTHLY, 1,
+ MyMoneySchedule::STYPE_DIRECTDEBIT,
+ QDate::currentDate(),
+ QDate(),
+ true,
+ true);
+
+ MyMoneyTransaction t10;
+ t10.setPostDate(QDate::currentDate().addMonths(1));
+ t10.setEntryDate(QDate::currentDate().addMonths(1));
+ //t.setId("T000000000000000001");
+ t10.setBankID("BID");
+ t10.setMemo("Wohnung:Miete");
+ t10.setCommodity("USD");
+ t10.setValue("key", "value");
+
+ MyMoneySplit s;
+ s.setPayeeId("P000001");
+ s.setShares(moT2);
+ s.setValue(moT2);
+ s.setAccountId(a_parent.id());
+ s.setBankID("SPID1");
+ s.setReconcileFlag(MyMoneySplit::Reconciled);
+ t10.addSplit(s);
+
+ s.setPayeeId("P000001");
+ s.setShares(-moT2);
+ s.setValue(-moT2);
+ s.setAccountId(a_cash.id());
+ s.setBankID("SPID2");
+ s.setReconcileFlag(MyMoneySplit::Cleared);
+ s.clearId();
+ t10.addSplit(s);
+
+ sch.setTransaction(t10);
+
+ file->addSchedule(sch);
+ ft.commit();
+
+ //run forecast
+ MyMoneyForecast c;
+ c.setForecastMethod(0);
+ c.setForecastCycles(1);
+ c.createBudget(budget, QDate::currentDate().addYears(-2), QDate::currentDate().addYears(-1), QDate::currentDate().addMonths(-2), QDate::currentDate().addMonths(6), true);
+
+ MyMoneyMoney c_parent = c.forecastBalance(a_parent, QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1) );
+
+ //test valid results
+ CPPUNIT_ASSERT(c.forecastBalance(a_parent, QDate(QDate::currentDate().addMonths(1).year(), QDate::currentDate().addMonths(1).month(), 1) ) == (moT2));
+}
+
+void MyMoneyForecastTest::testLinearRegression() {
+ //set up environment
+ MyMoneyForecast a;
+
+ MyMoneyAccount a_checking = file->account(acChecking);
+ MyMoneyAccount a_credit = file->account(acCredit);
+
+ //setup some transactions
+ TransactionHelper t1( QDate::currentDate().addDays(-1), MyMoneySplit::ActionWithdrawal, this->moT1, acChecking, acSolo);
+ TransactionHelper t2( QDate::currentDate().addDays(-1), MyMoneySplit::ActionDeposit, -(this->moT2), acCredit, acParent);
+ TransactionHelper t3( QDate::currentDate().addDays(-1), MyMoneySplit::ActionTransfer, this->moT1, acCredit, acChecking);
+
+//TODO Add tests specific for linear regression
+
+
+}