File indexing completed on 2024-05-26 05:08:46

0001 /*
0002     SPDX-FileCopyrightText: 2002-2019 Thomas Baumgart <tbaumgart@kde.org>
0003     SPDX-FileCopyrightText: 2004 Ace Jones <acejones@users.sourceforge.net>
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "mymoneyfile-test.h"
0008 #include <iostream>
0009 
0010 #include <memory>
0011 #include <QFile>
0012 #include <QDataStream>
0013 #include <QList>
0014 #include <QTest>
0015 
0016 #include "mymoneytestutils.h"
0017 #include "mymoneyexception.h"
0018 #include "mymoneymoney.h"
0019 #include "mymoneyinstitution.h"
0020 #include "mymoneyaccount.h"
0021 #include "mymoneysecurity.h"
0022 #include "mymoneytransaction.h"
0023 #include "mymoneytransactionfilter.h"
0024 #include "mymoneysplit.h"
0025 #include "mymoneyprice.h"
0026 #include "mymoneypayee.h"
0027 #include "mymoneyenums.h"
0028 #include "onlinejob.h"
0029 #include "payeesmodel.h"
0030 #include "accountsmodel.h"
0031 
0032 #include "payeeidentifier/ibanbic/ibanbic.h"
0033 #include "payeeidentifiertyped.h"
0034 
0035 QTEST_GUILESS_MAIN(MyMoneyFileTest)
0036 
0037 MyMoneyFileTest::MyMoneyFileTest()
0038     : m(nullptr)
0039 {
0040 }
0041 
0042 void MyMoneyFileTest::objectAdded(eMyMoney::File::Object type, const QString& id)
0043 {
0044     Q_UNUSED(type);
0045     m_objectsAdded += id;
0046 }
0047 
0048 void MyMoneyFileTest::objectRemoved(eMyMoney::File::Object type, const QString& id)
0049 {
0050     Q_UNUSED(type);
0051     m_objectsRemoved += id;
0052 }
0053 
0054 void MyMoneyFileTest::objectModified(eMyMoney::File::Object type, const QString& id)
0055 {
0056     Q_UNUSED(type);
0057     m_objectsModified += id;
0058 }
0059 
0060 void MyMoneyFileTest::clearObjectLists()
0061 {
0062     m_objectsAdded.clear();
0063     m_objectsModified.clear();
0064     m_objectsRemoved.clear();
0065     m_balanceChanged.clear();
0066     m_valueChanged.clear();
0067 }
0068 
0069 void MyMoneyFileTest::balanceChanged(const MyMoneyAccount& account)
0070 {
0071     m_balanceChanged += account.id();
0072 }
0073 
0074 void MyMoneyFileTest::valueChanged(const MyMoneyAccount& account)
0075 {
0076     m_valueChanged += account.id();
0077 }
0078 
0079 void MyMoneyFileTest::setupBaseCurrency()
0080 {
0081     MyMoneySecurity base("EUR", "Euro", QChar(0x20ac));
0082     MyMoneyFileTransaction ft;
0083     try {
0084         m->currency(base.id());
0085     } catch (const MyMoneyException&) {
0086         m->addCurrency(base);
0087     }
0088     m->setBaseCurrency(base);
0089     ft.commit();
0090 }
0091 
0092 // this method will be called once at the beginning of the test
0093 void MyMoneyFileTest::initTestCase()
0094 {
0095     m = MyMoneyFile::instance();
0096 
0097     connect(m, &MyMoneyFile::objectAdded, this, &MyMoneyFileTest::objectAdded);
0098     connect(m, &MyMoneyFile::objectRemoved, this, &MyMoneyFileTest::objectRemoved);
0099     connect(m, &MyMoneyFile::objectModified, this, &MyMoneyFileTest::objectModified);
0100     connect(m, &MyMoneyFile::balanceChanged, this, &MyMoneyFileTest::balanceChanged);
0101     connect(m, &MyMoneyFile::valueChanged, this, &MyMoneyFileTest::valueChanged);
0102 }
0103 
0104 // this method will be called before each testfunction
0105 void MyMoneyFileTest::init()
0106 {
0107     clearObjectLists();
0108 }
0109 
0110 // this method will be called after each testfunction
0111 void MyMoneyFileTest::cleanup()
0112 {
0113     m->unload();
0114 }
0115 
0116 void MyMoneyFileTest::testEmptyConstructor()
0117 {
0118     MyMoneyPayee user = m->user();
0119 
0120     QCOMPARE(user.name(), QString());
0121     QCOMPARE(user.address(), QString());
0122     QCOMPARE(user.city(), QString());
0123     QCOMPARE(user.state(), QString());
0124     QCOMPARE(user.postcode(), QString());
0125     QCOMPARE(user.telephone(), QString());
0126     QCOMPARE(user.email(), QString());
0127 
0128     QCOMPARE(m->institutionCount(), static_cast<unsigned>(0));
0129     QCOMPARE(m->dirty(), false);
0130     QCOMPARE(m->accountsModel()->itemList().count(), 0);
0131 }
0132 
0133 void MyMoneyFileTest::testAddOneInstitution()
0134 {
0135     MyMoneyInstitution institution;
0136 
0137     institution.setName("institution1");
0138     institution.setTown("town");
0139     institution.setStreet("street");
0140     institution.setPostcode("postcode");
0141     institution.setTelephone("telephone");
0142     institution.setManager("manager");
0143     institution.setBankCode("sortcode");
0144 
0145     // MyMoneyInstitution institution_file("", institution);
0146     MyMoneyInstitution institution_id("I000002", institution);
0147     MyMoneyInstitution institution_noname(institution);
0148     institution_noname.setName(QString());
0149 
0150     QCOMPARE(m->institutionCount(), static_cast<unsigned>(0));
0151 
0152     m->setDirty(false);
0153 
0154     clearObjectLists();
0155     MyMoneyFileTransaction ft;
0156     try {
0157         m->addInstitution(institution);
0158         ft.commit();
0159         QCOMPARE(institution.id(), QLatin1String("I000001"));
0160         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0161         QCOMPARE(m->dirty(), true);
0162 
0163         QCOMPARE(m_objectsRemoved.count(), 0);
0164         QCOMPARE(m_objectsAdded.count(), 1);
0165         QCOMPARE(m_objectsModified.count(), 0);
0166         QCOMPARE(m_balanceChanged.count(), 0);
0167         QCOMPARE(m_valueChanged.count(), 0);
0168         QCOMPARE(m_objectsAdded[0], QLatin1String("I000001"));
0169     } catch (const MyMoneyException &) {
0170         QFAIL("Unexpected exception");
0171     }
0172 
0173     clearObjectLists();
0174     ft.restart();
0175     try {
0176         m->addInstitution(institution_id);
0177         QFAIL("Missing expected exception");
0178     } catch (const MyMoneyException &) {
0179         ft.commit();
0180         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0181     }
0182 
0183     ft.restart();
0184     try {
0185         m->addInstitution(institution_noname);
0186         QFAIL("Missing expected exception");
0187     } catch (const MyMoneyException &) {
0188         ft.commit();
0189         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0190     }
0191     QCOMPARE(m_objectsRemoved.count(), 0);
0192     QCOMPARE(m_objectsAdded.count(), 0);
0193     QCOMPARE(m_objectsModified.count(), 0);
0194     QCOMPARE(m_balanceChanged.count(), 0);
0195     QCOMPARE(m_valueChanged.count(), 0);
0196 }
0197 
0198 void MyMoneyFileTest::testAddTwoInstitutions()
0199 {
0200     testAddOneInstitution();
0201     MyMoneyInstitution institution;
0202     institution.setName("institution2");
0203     institution.setTown("town");
0204     institution.setStreet("street");
0205     institution.setPostcode("postcode");
0206     institution.setTelephone("telephone");
0207     institution.setManager("manager");
0208     institution.setBankCode("sortcode");
0209 
0210     m->setDirty(false);
0211 
0212     MyMoneyFileTransaction ft;
0213     try {
0214         m->addInstitution(institution);
0215         ft.commit();
0216 
0217         QCOMPARE(institution.id(), QLatin1String("I000002"));
0218         QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0219         QCOMPARE(m->dirty(), true);
0220     } catch (const MyMoneyException &) {
0221         QFAIL("Unexpected exception");
0222     }
0223 
0224     m->setDirty(false);
0225 
0226     try {
0227         institution = m->institution("I000001");
0228         QCOMPARE(institution.id(), QLatin1String("I000001"));
0229         QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0230         QCOMPARE(m->dirty(), false);
0231 
0232         institution = m->institution("I000002");
0233         QCOMPARE(institution.id(), QLatin1String("I000002"));
0234         QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0235         QCOMPARE(m->dirty(), false);
0236     } catch (const MyMoneyException &) {
0237         QFAIL("Unexpected exception");
0238     }
0239 }
0240 
0241 void MyMoneyFileTest::testRemoveInstitution()
0242 {
0243     testAddTwoInstitutions();
0244 
0245     MyMoneyInstitution i;
0246 
0247     QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0248 
0249     i = m->institution("I000001");
0250     QCOMPARE(i.id(), QLatin1String("I000001"));
0251     QCOMPARE(i.accountCount(), static_cast<unsigned>(0));
0252 
0253     clearObjectLists();
0254 
0255     m->setDirty(false);
0256     MyMoneyFileTransaction ft;
0257     try {
0258         m->removeInstitution(i);
0259         QCOMPARE(m_objectsRemoved.count(), 0);
0260         ft.commit();
0261         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0262         QCOMPARE(m->dirty(), true);
0263         QCOMPARE(m_objectsRemoved.count(), 1);
0264         QCOMPARE(m_objectsAdded.count(), 0);
0265         QCOMPARE(m_objectsModified.count(), 0);
0266         QCOMPARE(m_balanceChanged.count(), 0);
0267         QCOMPARE(m_valueChanged.count(), 0);
0268         QCOMPARE(m_objectsRemoved[0], QLatin1String("I000001"));
0269     } catch (const MyMoneyException &) {
0270         QFAIL("Unexpected exception");
0271     }
0272 
0273     m->setDirty(false);
0274 
0275     try {
0276         m->institution("I000001");
0277         QFAIL("Missing expected exception");
0278     } catch (const MyMoneyException &) {
0279         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0280         QCOMPARE(m->dirty(), false);
0281     }
0282 
0283     clearObjectLists();
0284     ft.restart();
0285     try {
0286         m->removeInstitution(i);
0287         QFAIL("Missing expected exception");
0288     } catch (const MyMoneyException &) {
0289         ft.commit();
0290         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0291         QCOMPARE(m->dirty(), false);
0292         QCOMPARE(m_objectsRemoved.count(), 0);
0293     }
0294 }
0295 
0296 void MyMoneyFileTest::testInstitutionRetrieval()
0297 {
0298 
0299     testAddOneInstitution();
0300 
0301     m->setDirty(false);
0302 
0303     MyMoneyInstitution institution;
0304 
0305     QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0306 
0307     try {
0308         institution = m->institution("I000001");
0309         QCOMPARE(institution.id(), QLatin1String("I000001"));
0310         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0311     } catch (const MyMoneyException &) {
0312         QFAIL("Unexpected exception");
0313     }
0314 
0315     try {
0316         institution = m->institution("I000002");
0317         QFAIL("Missing expected exception");
0318     } catch (const MyMoneyException &) {
0319         QCOMPARE(m->institutionCount(), static_cast<unsigned>(1));
0320     }
0321 
0322     QCOMPARE(m->dirty(), false);
0323 }
0324 
0325 void MyMoneyFileTest::testInstitutionListRetrieval()
0326 {
0327     QList<MyMoneyInstitution> list;
0328 
0329     m->setDirty(false);
0330     list = m->institutionList();
0331     QCOMPARE(m->dirty(), false);
0332     QCOMPARE(list.count(), 0);
0333 
0334     testAddTwoInstitutions();
0335 
0336     m->setDirty(false);
0337     list = m->institutionList();
0338     QCOMPARE(m->dirty(), false);
0339     QCOMPARE(list.count(), 2);
0340 
0341     QList<MyMoneyInstitution>::ConstIterator it;
0342     it = list.constBegin();
0343 
0344     QVERIFY((*it).name() == "institution1" || (*it).name() == "institution2");
0345     ++it;
0346     QVERIFY((*it).name() == "institution2"  || (*it).name() == "institution1");
0347     ++it;
0348     QVERIFY(it == list.constEnd());
0349 }
0350 
0351 void MyMoneyFileTest::testInstitutionModify()
0352 {
0353     testAddTwoInstitutions();
0354     MyMoneyInstitution institution;
0355 
0356     institution = m->institution("I000001");
0357     institution.setStreet("new street");
0358     institution.setTown("new town");
0359     institution.setPostcode("new postcode");
0360     institution.setTelephone("new telephone");
0361     institution.setManager("new manager");
0362     institution.setName("new name");
0363     institution.setBankCode("new sortcode");
0364 
0365     m->setDirty(false);
0366 
0367     clearObjectLists();
0368     MyMoneyFileTransaction ft;
0369     try {
0370         m->modifyInstitution(institution);
0371         ft.commit();
0372         QCOMPARE(institution.id(), QLatin1String("I000001"));
0373         QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0374         QCOMPARE(m->dirty(), true);
0375 
0376         QCOMPARE(m_objectsRemoved.count(), 0);
0377         QCOMPARE(m_objectsAdded.count(), 0);
0378         QCOMPARE(m_objectsModified.count(), 1);
0379         QCOMPARE(m_balanceChanged.count(), 0);
0380         QCOMPARE(m_valueChanged.count(), 0);
0381         QCOMPARE(m_objectsModified[0], QLatin1String("I000001"));
0382     } catch (const MyMoneyException &) {
0383         QFAIL("Unexpected exception");
0384     }
0385 
0386     MyMoneyInstitution newInstitution;
0387     newInstitution = m->institution("I000001");
0388 
0389     QCOMPARE(newInstitution.id(), QLatin1String("I000001"));
0390     QCOMPARE(newInstitution.street(), QLatin1String("new street"));
0391     QCOMPARE(newInstitution.town(), QLatin1String("new town"));
0392     QCOMPARE(newInstitution.postcode(), QLatin1String("new postcode"));
0393     QCOMPARE(newInstitution.telephone(), QLatin1String("new telephone"));
0394     QCOMPARE(newInstitution.manager(), QLatin1String("new manager"));
0395     QCOMPARE(newInstitution.name(), QLatin1String("new name"));
0396     QCOMPARE(newInstitution.bankcode(), QLatin1String("new sortcode"));
0397 
0398     m->setDirty(false);
0399 
0400     ft.restart();
0401     MyMoneyInstitution failInstitution2("I000003", newInstitution);
0402     try {
0403         m->modifyInstitution(failInstitution2);
0404         QFAIL("Exception expected");
0405     } catch (const MyMoneyException &) {
0406         ft.commit();
0407         QCOMPARE(failInstitution2.id(), QLatin1String("I000003"));
0408         QCOMPARE(m->institutionCount(), static_cast<unsigned>(2));
0409         QCOMPARE(m->dirty(), false);
0410     }
0411 }
0412 
0413 void MyMoneyFileTest::testSetFunctions()
0414 {
0415     MyMoneyPayee user = m->user();
0416 
0417     QCOMPARE(user.name(), QString());
0418     QCOMPARE(user.address(), QString());
0419     QCOMPARE(user.city(), QString());
0420     QCOMPARE(user.state(), QString());
0421     QCOMPARE(user.postcode(), QString());
0422     QCOMPARE(user.telephone(), QString());
0423     QCOMPARE(user.email(), QString());
0424 
0425     MyMoneyFileTransaction ft;
0426     m->setDirty(false);
0427     user.setName("Name");
0428     m->setUser(user);
0429     QCOMPARE(m->dirty(), true);
0430     m->setDirty(false);
0431     user.setAddress("Street");
0432     m->setUser(user);
0433     QCOMPARE(m->dirty(), true);
0434     m->setDirty(false);
0435     user.setCity("Town");
0436     m->setUser(user);
0437     QCOMPARE(m->dirty(), true);
0438     m->setDirty(false);
0439     user.setState("County");
0440     m->setUser(user);
0441     QCOMPARE(m->dirty(), true);
0442     m->setDirty(false);
0443     user.setPostcode("Postcode");
0444     m->setUser(user);
0445     QCOMPARE(m->dirty(), true);
0446     m->setDirty(false);
0447     user.setTelephone("Telephone");
0448     m->setUser(user);
0449     QCOMPARE(m->dirty(), true);
0450     m->setDirty(false);
0451     user.setEmail("Email");
0452     m->setUser(user);
0453     QCOMPARE(m->dirty(), true);
0454     m->setDirty(false);
0455 
0456     ft.commit();
0457     user = m->user();
0458     QCOMPARE(user.name(), QLatin1String("Name"));
0459     QCOMPARE(user.address(), QLatin1String("Street"));
0460     QCOMPARE(user.city(), QLatin1String("Town"));
0461     QCOMPARE(user.state(), QLatin1String("County"));
0462     QCOMPARE(user.postcode(), QLatin1String("Postcode"));
0463     QCOMPARE(user.telephone(), QLatin1String("Telephone"));
0464     QCOMPARE(user.email(), QLatin1String("Email"));
0465 }
0466 
0467 void MyMoneyFileTest::testAddAccounts()
0468 {
0469     testAddTwoInstitutions();
0470     setupBaseCurrency();
0471     MyMoneyAccount  a, b, c;
0472     a.setAccountType(eMyMoney::Account::Type::Checkings);
0473     b.setAccountType(eMyMoney::Account::Type::Checkings);
0474 
0475     MyMoneyInstitution institution;
0476 
0477     m->setDirty(false);
0478 
0479     QCOMPARE(m->accountsModel()->itemList().count(), 0);
0480 
0481     institution = m->institution("I000001");
0482     QCOMPARE(institution.id(), QLatin1String("I000001"));
0483 
0484     a.setName("Account1");
0485     a.setInstitutionId(institution.id());
0486     a.setCurrencyId("EUR");
0487 
0488     clearObjectLists();
0489     MyMoneyFileTransaction ft;
0490     try {
0491         MyMoneyAccount parent = m->asset();
0492         m->addAccount(a, parent);
0493         ft.commit();
0494         QCOMPARE(m->accountsModel()->itemList().count(), 1);
0495         QCOMPARE(a.parentAccountId(), QLatin1String("AStd::Asset"));
0496         QCOMPARE(a.id(), QLatin1String("A000001"));
0497         QCOMPARE(a.institutionId(), QLatin1String("I000001"));
0498         QCOMPARE(a.currencyId(), QLatin1String("EUR"));
0499         QCOMPARE(m->dirty(), true);
0500         QCOMPARE(m->asset().accountList().count(), 1);
0501         QCOMPARE(m->asset().accountList().at(0), QLatin1String("A000001"));
0502 
0503         institution = m->institution("I000001");
0504         QCOMPARE(institution.accountCount(), static_cast<unsigned>(1));
0505         QCOMPARE(institution.accountList().at(0), QLatin1String("A000001"));
0506 
0507         QCOMPARE(m_objectsRemoved.count(), 0);
0508         QCOMPARE(m_objectsAdded.count(), 1);
0509         QCOMPARE(m_objectsModified.count(), 2);
0510         QCOMPARE(m_balanceChanged.count(), 0);
0511         QCOMPARE(m_valueChanged.count(), 0);
0512         QVERIFY(m_objectsAdded.contains(QLatin1String("A000001")));
0513         QVERIFY(m_objectsModified.contains(QLatin1String("I000001")));
0514         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
0515 
0516     } catch (const MyMoneyException &) {
0517         QFAIL("Unexpected exception!");
0518     }
0519 
0520     // try to add this account again, should not work
0521     ft.restart();
0522     try {
0523         MyMoneyAccount parent = m->asset();
0524         m->addAccount(a, parent);
0525         QFAIL("Expecting exception!");
0526     } catch (const MyMoneyException &) {
0527         ft.commit();
0528     }
0529 
0530     // check that we can modify the local object and
0531     // reload it from the file
0532     a.setName("AccountX");
0533     a = m->account("A000001");
0534     QCOMPARE(a.name(), QLatin1String("Account1"));
0535 
0536     m->setDirty(false);
0537 
0538     // check if we can get the same info to a different object
0539     c = m->account("A000001");
0540     QCOMPARE(c.accountType(), eMyMoney::Account::Type::Checkings);
0541     QCOMPARE(c.id(), QLatin1String("A000001"));
0542     QCOMPARE(c.name(), QLatin1String("Account1"));
0543     QCOMPARE(c.institutionId(), QLatin1String("I000001"));
0544 
0545     QCOMPARE(m->dirty(), false);
0546 
0547     // add a second account
0548     institution = m->institution("I000002");
0549     b.setName("Account2");
0550     b.setInstitutionId(institution.id());
0551     b.setCurrencyId("EUR");
0552     clearObjectLists();
0553     ft.restart();
0554     try {
0555         MyMoneyAccount parent = m->asset();
0556         m->addAccount(b, parent);
0557         ft.commit();
0558         QCOMPARE(m->dirty(), true);
0559         QCOMPARE(b.id(), QLatin1String("A000002"));
0560         QCOMPARE(b.currencyId(), QLatin1String("EUR"));
0561         QCOMPARE(b.parentAccountId(), QLatin1String("AStd::Asset"));
0562         QCOMPARE(m->accountsModel()->itemList().count(), 2);
0563 
0564         institution = m->institution("I000001");
0565         QCOMPARE(institution.accountCount(), static_cast<unsigned>(1));
0566         QCOMPARE(institution.accountList().at(0), QLatin1String("A000001"));
0567 
0568         institution = m->institution("I000002");
0569         QCOMPARE(institution.accountCount(), static_cast<unsigned>(1));
0570         QCOMPARE(institution.accountList().at(0), QLatin1String("A000002"));
0571 
0572         QCOMPARE(m->asset().accountList().count(), 2);
0573         QCOMPARE(m->asset().accountList().at(0), QLatin1String("A000001"));
0574         QCOMPARE(m->asset().accountList().at(1), QLatin1String("A000002"));
0575 
0576         QCOMPARE(m_objectsRemoved.count(), 0);
0577         QCOMPARE(m_objectsAdded.count(), 1);
0578         QCOMPARE(m_objectsModified.count(), 2);
0579         QCOMPARE(m_balanceChanged.count(), 0);
0580         QCOMPARE(m_valueChanged.count(), 0);
0581         QVERIFY(m_objectsAdded.contains(QLatin1String("A000002")));
0582         QVERIFY(m_objectsModified.contains(QLatin1String("I000002")));
0583         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
0584 
0585     } catch (const MyMoneyException &) {
0586         QFAIL("Unexpected exception!");
0587     }
0588 
0589     MyMoneyAccount p;
0590 
0591     p = m->account("A000002");
0592     QCOMPARE(p.accountType(), eMyMoney::Account::Type::Checkings);
0593     QCOMPARE(p.id(), QLatin1String("A000002"));
0594     QCOMPARE(p.name(), QLatin1String("Account2"));
0595     QCOMPARE(p.institutionId(), QLatin1String("I000002"));
0596     QCOMPARE(p.currencyId(), QLatin1String("EUR"));
0597 }
0598 
0599 void MyMoneyFileTest::testAddCategories()
0600 {
0601     setupBaseCurrency();
0602 
0603     MyMoneyAccount  a, b, c;
0604     a.setAccountType(eMyMoney::Account::Type::Income);
0605     a.setOpeningDate(QDate::currentDate());
0606     b.setAccountType(eMyMoney::Account::Type::Expense);
0607 
0608     m->setDirty(false);
0609 
0610     QCOMPARE(m->accountsModel()->itemList().count(), 0);
0611     QCOMPARE(a.openingDate(), QDate::currentDate());
0612     QVERIFY(!b.openingDate().isValid());
0613 
0614     a.setName("Account1");
0615     a.setCurrencyId("EUR");
0616 
0617     clearObjectLists();
0618     MyMoneyFileTransaction ft;
0619     try {
0620         MyMoneyAccount parent = m->income();
0621         m->addAccount(a, parent);
0622         ft.commit();
0623         QCOMPARE(m->accountsModel()->itemList().count(), 1);
0624         QCOMPARE(a.parentAccountId(), QLatin1String("AStd::Income"));
0625         QCOMPARE(a.id(), QLatin1String("A000001"));
0626         QCOMPARE(a.institutionId(), QString());
0627         QCOMPARE(a.currencyId(), QLatin1String("EUR"));
0628         QCOMPARE(a.openingDate(), QDate(1900, 1, 1));
0629         QCOMPARE(m->dirty(), true);
0630         QCOMPARE(m->income().accountList().count(), 1);
0631         QCOMPARE(m->income().accountList()[0], QLatin1String("A000001"));
0632 
0633     } catch (const MyMoneyException &) {
0634         QFAIL("Unexpected exception!");
0635     }
0636 
0637     // add a second category, expense this time
0638     b.setName("Account2");
0639     b.setCurrencyId("EUR");
0640     clearObjectLists();
0641     ft.restart();
0642     try {
0643         MyMoneyAccount parent = m->expense();
0644         m->addAccount(b, parent);
0645         ft.commit();
0646         QCOMPARE(m->dirty(), true);
0647         QCOMPARE(b.id(), QLatin1String("A000002"));
0648         QCOMPARE(a.institutionId(), QString());
0649         QCOMPARE(b.currencyId(), QLatin1String("EUR"));
0650         QCOMPARE(b.openingDate(), QDate(1900, 1, 1));
0651         QCOMPARE(b.parentAccountId(), QLatin1String("AStd::Expense"));
0652         QCOMPARE(m->accountsModel()->itemList().count(), 2);
0653 
0654         QCOMPARE(m->income().accountList().count(), 1);
0655         QCOMPARE(m->expense().accountList().count(), 1);
0656         QCOMPARE(m->income().accountList()[0], QLatin1String("A000001"));
0657         QCOMPARE(m->expense().accountList()[0], QLatin1String("A000002"));
0658 
0659         QCOMPARE(m_objectsRemoved.count(), 0);
0660         QCOMPARE(m_objectsAdded.count(), 1);
0661         QCOMPARE(m_objectsModified.count(), 1);
0662         QCOMPARE(m_balanceChanged.count(), 0);
0663         QCOMPARE(m_valueChanged.count(), 0);
0664         QVERIFY(m_objectsAdded.contains(QLatin1String("A000002")));
0665         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Expense")));
0666 
0667     } catch (const MyMoneyException &) {
0668         QFAIL("Unexpected exception!");
0669     }
0670 }
0671 
0672 void MyMoneyFileTest::testModifyAccount()
0673 {
0674     testAddAccounts();
0675     m->setDirty(false);
0676 
0677     MyMoneyAccount p = m->account("A000001");
0678     MyMoneyInstitution institution;
0679 
0680     QCOMPARE(p.accountType(), eMyMoney::Account::Type::Checkings);
0681     QCOMPARE(p.name(), QLatin1String("Account1"));
0682 
0683     p.setName("New account name");
0684     MyMoneyFileTransaction ft;
0685     clearObjectLists();
0686     try {
0687         m->modifyAccount(p);
0688         ft.commit();
0689 
0690         QCOMPARE(m->dirty(), true);
0691         QCOMPARE(m->accountsModel()->itemList().count(), 2);
0692         QCOMPARE(p.accountType(), eMyMoney::Account::Type::Checkings);
0693         QCOMPARE(p.name(), QLatin1String("New account name"));
0694 
0695         QCOMPARE(m_objectsRemoved.count(), 0);
0696         QCOMPARE(m_objectsAdded.count(), 0);
0697         QCOMPARE(m_objectsModified.count(), 1);
0698         QCOMPARE(m_balanceChanged.count(), 0);
0699         QCOMPARE(m_valueChanged.count(), 0);
0700         QVERIFY(m_objectsModified.contains(QLatin1String("A000001")));
0701 
0702     } catch (const MyMoneyException &) {
0703         QFAIL("Unexpected exception!");
0704     }
0705     m->setDirty(false);
0706 
0707     // try to move account to new institution
0708     p.setInstitutionId("I000002");
0709     ft.restart();
0710     clearObjectLists();
0711     try {
0712         m->modifyAccount(p);
0713         ft.commit();
0714 
0715         QCOMPARE(m->dirty(), true);
0716         QCOMPARE(m->accountsModel()->itemList().count(), 2);
0717         QCOMPARE(p.accountType(), eMyMoney::Account::Type::Checkings);
0718         QCOMPARE(p.name(), QLatin1String("New account name"));
0719         QCOMPARE(p.institutionId(), QLatin1String("I000002"));
0720 
0721         institution = m->institution("I000001");
0722         QCOMPARE(institution.accountCount(), static_cast<unsigned>(0));
0723 
0724         institution = m->institution("I000002");
0725         QCOMPARE(institution.accountCount(), static_cast<unsigned>(2));
0726         QCOMPARE(institution.accountList().at(0), QLatin1String("A000002"));
0727         QCOMPARE(institution.accountList().at(1), QLatin1String("A000001"));
0728 
0729         QCOMPARE(m_objectsRemoved.count(), 0);
0730         QCOMPARE(m_objectsAdded.count(), 0);
0731         QCOMPARE(m_objectsModified.count(), 3);
0732         QCOMPARE(m_balanceChanged.count(), 0);
0733         QCOMPARE(m_valueChanged.count(), 0);
0734         QVERIFY(m_objectsModified.contains(QLatin1String("A000001")));
0735         QVERIFY(m_objectsModified.contains(QLatin1String("I000001")));
0736         QVERIFY(m_objectsModified.contains(QLatin1String("I000002")));
0737 
0738     } catch (const MyMoneyException &) {
0739         QFAIL("Unexpected exception!");
0740     }
0741     m->setDirty(false);
0742 
0743     // try to change to an account type that is allowed
0744     p.setAccountType(eMyMoney::Account::Type::Savings);
0745     ft.restart();
0746     try {
0747         m->modifyAccount(p);
0748         ft.commit();
0749 
0750         QCOMPARE(m->dirty(), true);
0751         QCOMPARE(m->accountsModel()->itemList().count(), 2);
0752         QCOMPARE(p.accountType(), eMyMoney::Account::Type::Savings);
0753         QCOMPARE(p.name(), QLatin1String("New account name"));
0754 
0755     } catch (const MyMoneyException &) {
0756         QFAIL("Unexpected exception!");
0757     }
0758     m->setDirty(false);
0759 
0760     // try to change to an account type that is not allowed
0761     p.setAccountType(eMyMoney::Account::Type::CreditCard);
0762     ft.restart();
0763     try {
0764         m->modifyAccount(p);
0765         QFAIL("Expecting exception!");
0766     } catch (const MyMoneyException &) {
0767         ft.commit();
0768     }
0769     m->setDirty(false);
0770 
0771     // try to fool engine a bit
0772     p.setParentAccountId("A000001");
0773     ft.restart();
0774     try {
0775         m->modifyAccount(p);
0776         QFAIL("Expecting exception!");
0777     } catch (const MyMoneyException &) {
0778         ft.commit();
0779     }
0780 }
0781 
0782 void MyMoneyFileTest::testReparentAccount()
0783 {
0784     testAddAccounts();
0785     m->setDirty(false);
0786 
0787     MyMoneyAccount p = m->account("A000001");
0788     MyMoneyAccount q = m->account("A000002");
0789     MyMoneyAccount o = m->account(p.parentAccountId());
0790 
0791     // make A000001 a child of A000002
0792     clearObjectLists();
0793     MyMoneyFileTransaction ft;
0794     try {
0795         QVERIFY(p.parentAccountId() != q.id());
0796         QCOMPARE(o.accountCount(), 2);
0797         QCOMPARE(q.accountCount(), 0);
0798         m->reparentAccount(p, q);
0799         ft.commit();
0800         QCOMPARE(m->dirty(), true);
0801         QCOMPARE(p.parentAccountId(), q.id());
0802         QCOMPARE(q.accountCount(), 1);
0803         QCOMPARE(q.id(), QLatin1String("A000002"));
0804         QCOMPARE(p.id(), QLatin1String("A000001"));
0805         QCOMPARE(q.accountList().at(0), p.id());
0806 
0807         QCOMPARE(m_objectsRemoved.count(), 0);
0808         QCOMPARE(m_objectsAdded.count(), 0);
0809         QCOMPARE(m_objectsModified.count(), 3);
0810         QCOMPARE(m_balanceChanged.count(), 0);
0811         QCOMPARE(m_valueChanged.count(), 0);
0812         QVERIFY(m_objectsModified.contains(QLatin1String("A000001")));
0813         QVERIFY(m_objectsModified.contains(QLatin1String("A000002")));
0814         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
0815 
0816         o = m->account(o.id());
0817         QCOMPARE(o.accountCount(), 1);
0818     } catch (const MyMoneyException &) {
0819         QFAIL("Unexpected exception!");
0820     }
0821 }
0822 
0823 void MyMoneyFileTest::testRemoveStdAccount(const MyMoneyAccount& acc)
0824 {
0825     QString txt("Exception expected while removing account ");
0826     txt += acc.id();
0827     MyMoneyFileTransaction ft;
0828     try {
0829         m->removeAccount(acc);
0830         QFAIL(qPrintable(txt));
0831     } catch (const MyMoneyException &) {
0832         ft.commit();
0833     }
0834 }
0835 
0836 void MyMoneyFileTest::testRemoveAccount()
0837 {
0838     MyMoneyInstitution institution;
0839 
0840     testAddAccounts();
0841     QCOMPARE(m->accountsModel()->itemList().count(), 2);
0842     m->setDirty(false);
0843 
0844     MyMoneyAccount p = m->account("A000001");
0845 
0846     clearObjectLists();
0847 
0848     MyMoneyFileTransaction ft;
0849     try {
0850         MyMoneyAccount q("Ainvalid", p);
0851         m->removeAccount(q);
0852         QFAIL("Exception expected!");
0853     } catch (const MyMoneyException &) {
0854         ft.commit();
0855     }
0856 
0857     ft.restart();
0858     try {
0859         QCOMPARE(m_objectsRemoved.count(), 0);
0860         QCOMPARE(m_objectsAdded.count(), 0);
0861         QCOMPARE(m_objectsModified.count(), 0);
0862 
0863         m->removeAccount(p);
0864         ft.commit();
0865         QCOMPARE(m->dirty(), true);
0866         QCOMPARE(m->accountsModel()->itemList().count(), 1);
0867         institution = m->institution("I000001");
0868         QCOMPARE(institution.accountCount(), static_cast<unsigned>(0));
0869         QCOMPARE(m->asset().accountList().count(), 1);
0870 
0871         QCOMPARE(m_objectsRemoved.count(), 1);
0872         QCOMPARE(m_objectsModified.count(), 2);
0873         QCOMPARE(m_objectsAdded.count(), 0);
0874         QCOMPARE(m_balanceChanged.count(), 0);
0875         QCOMPARE(m_valueChanged.count(), 0);
0876 
0877         QVERIFY(m_objectsRemoved.contains(QLatin1String("A000001")));
0878         QVERIFY(m_objectsModified.contains(QLatin1String("I000001")));
0879         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
0880 
0881         institution = m->institution("I000002");
0882         QCOMPARE(institution.accountCount(), static_cast<unsigned>(1));
0883 
0884     } catch (const MyMoneyException &) {
0885         QFAIL("Unexpected exception!");
0886     }
0887 
0888     // Check that the standard account-groups cannot be removed
0889     testRemoveStdAccount(m->liability());
0890     testRemoveStdAccount(m->asset());
0891     testRemoveStdAccount(m->expense());
0892     testRemoveStdAccount(m->income());
0893 }
0894 
0895 void MyMoneyFileTest::testRemoveAccountTree()
0896 {
0897     testReparentAccount();
0898     MyMoneyAccount a = m->account("A000002");
0899 
0900     clearObjectLists();
0901     MyMoneyFileTransaction ft;
0902     // remove the account
0903     try {
0904         m->removeAccount(a);
0905         ft.commit();
0906 
0907         QCOMPARE(m_objectsRemoved.count(), 1);
0908         QCOMPARE(m_objectsModified.count(), 5);
0909         QCOMPARE(m_objectsAdded.count(), 0);
0910         QCOMPARE(m_balanceChanged.count(), 0);
0911         QCOMPARE(m_valueChanged.count(), 0);
0912 
0913         QVERIFY(m_objectsRemoved.contains(QLatin1String("A000002")));
0914         QVERIFY(m_objectsModified.contains(QLatin1String("A000001")));
0915         QVERIFY(m_objectsModified.contains(QLatin1String("I000002")));
0916         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
0917 
0918     } catch (const MyMoneyException &) {
0919         QFAIL("Unexpected exception!");
0920     }
0921     QCOMPARE(m->accountsModel()->itemList().count(), 1);
0922 
0923     // make sure it's gone
0924     try {
0925         m->account("A000002");
0926         QFAIL("Exception expected!");
0927     } catch (const MyMoneyException &) {
0928     }
0929 
0930     // make sure that children are re-parented to parent account
0931     try {
0932         a = m->account("A000001");
0933         QCOMPARE(a.parentAccountId(), m->asset().id());
0934     } catch (const MyMoneyException &) {
0935         QFAIL("Unexpected exception!");
0936     }
0937 }
0938 
0939 void MyMoneyFileTest::testAccountListRetrieval()
0940 {
0941     QList<MyMoneyAccount> list;
0942 
0943     m->setDirty(false);
0944     m->accountList(list);
0945     QCOMPARE(m->dirty(), false);
0946     QCOMPARE(list.count(), 0);
0947 
0948     testAddAccounts();
0949 
0950     m->setDirty(false);
0951     list.clear();
0952     m->accountList(list);
0953     QCOMPARE(m->dirty(), false);
0954     QCOMPARE(list.count(), 2);
0955 
0956     QCOMPARE(list[0].accountType(), eMyMoney::Account::Type::Checkings);
0957     QCOMPARE(list[1].accountType(), eMyMoney::Account::Type::Checkings);
0958 }
0959 
0960 void MyMoneyFileTest::testAddTransaction()
0961 {
0962     testAddAccounts();
0963     setupBaseCurrency();
0964 
0965     MyMoneyTransaction t, p;
0966 
0967     MyMoneyAccount exp1;
0968     exp1.setAccountType(eMyMoney::Account::Type::Expense);
0969     exp1.setName("Expense1");
0970     MyMoneyAccount exp2;
0971     exp2.setAccountType(eMyMoney::Account::Type::Expense);
0972     exp2.setName("Expense2");
0973 
0974     MyMoneyFileTransaction ft;
0975     try {
0976         MyMoneyAccount parent = m->expense();
0977         m->addAccount(exp1, parent);
0978         m->addAccount(exp2, parent);
0979         ft.commit();
0980     } catch (const MyMoneyException &) {
0981         QFAIL("Unexpected exception!");
0982     }
0983 
0984     // fake the last modified flag to check that the
0985     // date is updated when we add the transaction
0986     MyMoneyAccount a = m->account("A000001");
0987     a.setLastModified(QDate(1, 2, 3));
0988     ft.restart();
0989     try {
0990         m->modifyAccount(a);
0991         ft.commit();
0992     } catch (const MyMoneyException &) {
0993         QFAIL("Unexpected exception!");
0994     }
0995     ft.restart();
0996 
0997     QCOMPARE(m->accountsModel()->itemList().count(), 4);
0998     a = m->account("A000001");
0999     QCOMPARE(a.lastModified(), QDate(1, 2, 3));
1000 
1001     // construct a transaction and add it to the pool
1002     t.setPostDate(QDate(2002, 2, 1));
1003     t.setMemo("Memotext");
1004 
1005     MyMoneySplit split1;
1006     MyMoneySplit split2;
1007 
1008     split1.setAccountId("A000001");
1009     split1.setShares(MyMoneyMoney(-1000, 100));
1010     split1.setValue(MyMoneyMoney(-1000, 100));
1011     split2.setAccountId("A000003");
1012     split2.setValue(MyMoneyMoney(1000, 100));
1013     split2.setShares(MyMoneyMoney(1000, 100));
1014     try {
1015         t.addSplit(split1);
1016         t.addSplit(split2);
1017     } catch (const MyMoneyException &) {
1018         QFAIL("Unexpected exception!");
1019     }
1020 
1021     /*
1022             // FIXME: we don't have a payee and a number field right now
1023             // guess we should have a number field per split, don't know
1024             // about the payee
1025             t.setMethod(MyMoneyCheckingTransaction::Withdrawal);
1026             t.setPayee("Thomas Baumgart");
1027             t.setNumber("1234");
1028             t.setState(MyMoneyCheckingTransaction::Cleared);
1029     */
1030     m->setDirty(false);
1031 
1032     ft.restart();
1033     clearObjectLists();
1034     try {
1035         m->addTransaction(t);
1036         ft.commit();
1037         QCOMPARE(m_objectsRemoved.count(), 0);
1038         QCOMPARE(m_objectsModified.count(), 0);
1039         QCOMPARE(m_objectsAdded.count(), 1);
1040         QCOMPARE(m_balanceChanged.count(), 2);
1041         QCOMPARE(m_balanceChanged.count("A000001"), 1);
1042         QCOMPARE(m_balanceChanged.count("A000003"), 1);
1043         QCOMPARE(m_valueChanged.count(), 0);
1044     } catch (const MyMoneyException &) {
1045         QFAIL("Unexpected exception!");
1046     }
1047     ft.restart();
1048     clearObjectLists();
1049 
1050     QCOMPARE(t.id(), QLatin1String("T000000000000000001"));
1051     QCOMPARE(t.postDate(), QDate(2002, 2, 1));
1052     QCOMPARE(t.entryDate(), QDate::currentDate());
1053     QCOMPARE(m->dirty(), true);
1054 
1055     // check the balance of the accounts
1056     a = m->account("A000001");
1057     QCOMPARE(a.lastModified(), QDate::currentDate());
1058     QCOMPARE(a.balance().toDouble(), MyMoneyMoney(-1000, 100).toDouble());
1059 
1060     MyMoneyAccount b = m->account("A000003");
1061     QCOMPARE(b.lastModified(), QDate::currentDate());
1062     QCOMPARE(b.balance(), MyMoneyMoney(1000, 100));
1063 
1064     m->setDirty(false);
1065 
1066     // locate transaction in MyMoneyFile via id
1067 
1068     try {
1069         p = m->transaction("T000000000000000001");
1070         QCOMPARE(m_balanceChanged.count(), 0);
1071         QCOMPARE(m_valueChanged.count(), 0);
1072         QCOMPARE(p.splitCount(), static_cast<unsigned>(2));
1073         QCOMPARE(p.memo(), QLatin1String("Memotext"));
1074         QCOMPARE(p.splits()[0].accountId(), QLatin1String("A000001"));
1075         QCOMPARE(p.splits()[1].accountId(), QLatin1String("A000003"));
1076     } catch (const MyMoneyException &) {
1077         QFAIL("Unexpected exception!");
1078     }
1079 
1080     // check if it's in the account(s) as well
1081 
1082     try {
1083         p = m->transaction("A000001", 0);
1084         QCOMPARE(m_balanceChanged.count(), 0);
1085         QCOMPARE(m_valueChanged.count(), 0);
1086         QCOMPARE(p.id(), QLatin1String("T000000000000000001"));
1087         QCOMPARE(p.splitCount(), static_cast<unsigned>(2));
1088         QCOMPARE(p.memo(), QLatin1String("Memotext"));
1089         QCOMPARE(p.splits()[0].accountId(), QLatin1String("A000001"));
1090         QCOMPARE(p.splits()[1].accountId(), QLatin1String("A000003"));
1091     } catch (const MyMoneyException &) {
1092         QFAIL("Unexpected exception!");
1093     }
1094 
1095     try {
1096         p = m->transaction("A000003", 0);
1097         QCOMPARE(m_balanceChanged.count(), 0);
1098         QCOMPARE(m_valueChanged.count(), 0);
1099         QCOMPARE(p.id(), QLatin1String("T000000000000000001"));
1100         QCOMPARE(p.splitCount(), static_cast<unsigned>(2));
1101         QCOMPARE(p.memo(), QLatin1String("Memotext"));
1102         QCOMPARE(p.splits()[0].accountId(), QLatin1String("A000001"));
1103         QCOMPARE(p.splits()[1].accountId(), QLatin1String("A000003"));
1104     } catch (const MyMoneyException &) {
1105         QFAIL("Unexpected exception!");
1106     }
1107 }
1108 
1109 void MyMoneyFileTest::testIsStandardAccount()
1110 {
1111     QCOMPARE(m->isStandardAccount(m->liability().id()), true);
1112     QCOMPARE(m->isStandardAccount(m->asset().id()), true);
1113     QCOMPARE(m->isStandardAccount(m->expense().id()), true);
1114     QCOMPARE(m->isStandardAccount(m->income().id()), true);
1115     QCOMPARE(m->isStandardAccount("A00001"), false);
1116 }
1117 
1118 void MyMoneyFileTest::testHasActiveSplits()
1119 {
1120     testAddTransaction();
1121 
1122     QCOMPARE(m->hasActiveSplits("A000001"), true);
1123     QCOMPARE(m->hasActiveSplits("A000002"), false);
1124 }
1125 
1126 void MyMoneyFileTest::testModifyTransactionSimple()
1127 {
1128     // this will test that we can modify the basic attributes
1129     // of a transaction
1130     testAddTransaction();
1131 
1132     MyMoneyTransaction t = m->transaction("T000000000000000001");
1133     t.setMemo("New Memotext");
1134     m->setDirty(false);
1135 
1136     MyMoneyFileTransaction ft;
1137     clearObjectLists();
1138     try {
1139         m->modifyTransaction(t);
1140         ft.commit();
1141         QCOMPARE(m_objectsRemoved.count(), 0);
1142         QCOMPARE(m_objectsModified.count(), 1);
1143         QCOMPARE(m_objectsAdded.count(), 0);
1144         QCOMPARE(m_balanceChanged.count(), 2);
1145         QCOMPARE(m_balanceChanged.count(QLatin1String("A000001")), 1);
1146         QCOMPARE(m_balanceChanged.count(QLatin1String("A000003")), 1);
1147         QCOMPARE(m_valueChanged.count(), 0);
1148         t = m->transaction("T000000000000000001");
1149         QCOMPARE(t.memo(), QLatin1String("New Memotext"));
1150         QCOMPARE(m->dirty(), true);
1151 
1152     } catch (const MyMoneyException &) {
1153         QFAIL("Unexpected exception!");
1154     }
1155 }
1156 
1157 void MyMoneyFileTest::testModifyTransactionNewPostDate()
1158 {
1159     // this will test that we can modify the basic attributes
1160     // of a transaction
1161     testAddTransaction();
1162 
1163     MyMoneyTransaction t = m->transaction("T000000000000000001");
1164     t.setPostDate(QDate(2004, 2, 1));
1165     m->setDirty(false);
1166 
1167     MyMoneyFileTransaction ft;
1168     clearObjectLists();
1169     try {
1170         m->modifyTransaction(t);
1171         ft.commit();
1172         t = m->transaction("T000000000000000001");
1173         QCOMPARE(t.postDate(), QDate(2004, 2, 1));
1174         t = m->transaction("A000001", 0);
1175         QCOMPARE(t.id(), QLatin1String("T000000000000000001"));
1176         QCOMPARE(m->dirty(), true);
1177 
1178         QCOMPARE(m_objectsRemoved.count(), 0);
1179         QCOMPARE(m_objectsModified.count(), 1);
1180         QCOMPARE(m_objectsAdded.count(), 0);
1181         QCOMPARE(m_balanceChanged.count(), 2);
1182         QCOMPARE(m_balanceChanged.count(QLatin1String("A000001")), 1);
1183         QCOMPARE(m_balanceChanged.count(QLatin1String("A000003")), 1);
1184         QCOMPARE(m_valueChanged.count(), 0);
1185     } catch (const MyMoneyException &) {
1186         QFAIL("Unexpected exception!");
1187     }
1188 }
1189 
1190 void MyMoneyFileTest::testModifyTransactionNewAccount()
1191 {
1192     // this will test that we can modify the basic attributes
1193     // of a transaction
1194     testAddTransaction();
1195 
1196     MyMoneyTransaction t = m->transaction("T000000000000000001");
1197     MyMoneySplit s;
1198     s = t.splits()[0];
1199     s.setAccountId("A000002");
1200     t.modifySplit(s);
1201 
1202     m->setDirty(false);
1203     QList<MyMoneyTransaction> list;
1204     MyMoneyFileTransaction ft;
1205     clearObjectLists();
1206     try {
1207         MyMoneyTransactionFilter f1("A000001");
1208         MyMoneyTransactionFilter f2("A000002");
1209         MyMoneyTransactionFilter f3("A000003");
1210         m->transactionList(list, f1);
1211         QCOMPARE(list.count(), 1);
1212         m->transactionList(list, f2);
1213         QCOMPARE(list.count(), 0);
1214         m->transactionList(list, f3);
1215         QCOMPARE(list.count(), 1);
1216 
1217         m->modifyTransaction(t);
1218         ft.commit();
1219         t = m->transaction("T000000000000000001");
1220         QCOMPARE(t.postDate(), QDate(2002, 2, 1));
1221         t = m->transaction("A000002", 0);
1222         QCOMPARE(m->dirty(), true);
1223         m->transactionList(list, f1);
1224         QCOMPARE(list.count(), 0);
1225         m->transactionList(list, f2);
1226         QCOMPARE(list.count(), 1);
1227         m->transactionList(list, f3);
1228         QCOMPARE(list.count(), 1);
1229 
1230         QCOMPARE(m_objectsRemoved.count(), 0);
1231         QCOMPARE(m_objectsModified.count(), 1);
1232         QCOMPARE(m_objectsAdded.count(), 0);
1233         QCOMPARE(m_balanceChanged.count(), 3);
1234         QCOMPARE(m_balanceChanged.count(QLatin1String("A000001")), 1);
1235         QCOMPARE(m_balanceChanged.count(QLatin1String("A000002")), 1);
1236         QCOMPARE(m_balanceChanged.count(QLatin1String("A000003")), 1);
1237         QCOMPARE(m_valueChanged.count(), 0);
1238 
1239 
1240     } catch (const MyMoneyException &) {
1241         QFAIL("Unexpected exception!");
1242     }
1243 }
1244 
1245 void MyMoneyFileTest::testRemoveTransaction()
1246 {
1247     testModifyTransactionNewPostDate();
1248 
1249     MyMoneyTransaction t;
1250     t = m->transaction("T000000000000000001");
1251 
1252     m->setDirty(false);
1253     MyMoneyFileTransaction ft;
1254     QList<MyMoneyTransaction> list;
1255     clearObjectLists();
1256     try {
1257         m->removeTransaction(t);
1258         ft.commit();
1259         QCOMPARE(m->dirty(), true);
1260         QCOMPARE(m->transactionCount(), static_cast<unsigned>(0));
1261         MyMoneyTransactionFilter f1("A000001");
1262         MyMoneyTransactionFilter f2("A000002");
1263         MyMoneyTransactionFilter f3("A000003");
1264         m->transactionList(list, f1);
1265         QCOMPARE(list.count(), 0);
1266         m->transactionList(list, f2);
1267         QCOMPARE(list.count(), 0);
1268         m->transactionList(list, f3);
1269         QCOMPARE(list.count(), 0);
1270 
1271         QCOMPARE(m_objectsRemoved.count(), 1);
1272         QCOMPARE(m_objectsModified.count(), 0);
1273         QCOMPARE(m_objectsAdded.count(), 0);
1274         QCOMPARE(m_balanceChanged.count(), 2);
1275         QCOMPARE(m_balanceChanged.count(QLatin1String("A000001")), 1);
1276         QCOMPARE(m_balanceChanged.count(QLatin1String("A000003")), 1);
1277         QCOMPARE(m_valueChanged.count(), 0);
1278 
1279     } catch (const MyMoneyException &) {
1280         QFAIL("Unexpected exception!");
1281     }
1282 }
1283 
1284 /*
1285  * This function is currently not implemented. It's kind of tricky
1286  * because it modifies a lot of objects in a single call. This might
1287  * be a problem for the undo/redo stuff. That's why I left it out in
1288  * the first run. We migh add it, if we need it.
1289  * /
1290 void testMoveSplits() {
1291         testModifyTransactionNewPostDate();
1292 
1293         QCOMPARE(m->account("A000001").transactionCount(), 1);
1294         QCOMPARE(m->account("A000002").transactionCount(), 0);
1295         QCOMPARE(m->account("A000003").transactionCount(), 1);
1296 
1297         try {
1298                 m->moveSplits("A000001", "A000002");
1299                 QCOMPARE(m->account("A000001").transactionCount(), 0);
1300                 QCOMPARE(m->account("A000002").transactionCount(), 1);
1301                 QCOMPARE(m->account("A000003").transactionCount(), 1);
1302         } catch (const MyMoneyException&) {
1303                 QFAIL("Unexpected exception!");
1304         }
1305 }
1306 */
1307 
1308 void MyMoneyFileTest::testBalanceTotal()
1309 {
1310     testAddTransaction();
1311     MyMoneyTransaction t;
1312 
1313     // construct a transaction and add it to the pool
1314     t.setPostDate(QDate(2002, 2, 1));
1315     t.setMemo("Memotext");
1316 
1317     MyMoneySplit split1;
1318     MyMoneySplit split2;
1319 
1320     MyMoneyFileTransaction ft;
1321     try {
1322         split1.setAccountId("A000002");
1323         split1.setShares(MyMoneyMoney(-1000, 100));
1324         split1.setValue(MyMoneyMoney(-1000, 100));
1325         split2.setAccountId("A000004");
1326         split2.setValue(MyMoneyMoney(1000, 100));
1327         split2.setShares(MyMoneyMoney(1000, 100));
1328         t.addSplit(split1);
1329         t.addSplit(split2);
1330         m->addTransaction(t);
1331         ft.commit();
1332         ft.restart();
1333         QCOMPARE(t.id(), QLatin1String("T000000000000000002"));
1334         QCOMPARE(m->totalBalance("A000001"), MyMoneyMoney(-1000, 100));
1335         QCOMPARE(m->totalBalance("A000002"), MyMoneyMoney(-1000, 100));
1336 
1337         MyMoneyAccount p = m->account("A000001");
1338         MyMoneyAccount q = m->account("A000002");
1339         m->reparentAccount(p, q);
1340         ft.commit();
1341         // check totalBalance() and balance() with combinations of parameters
1342         QCOMPARE(m->totalBalance("A000001"), MyMoneyMoney(-1000, 100));
1343         QCOMPARE(m->totalBalance("A000002"), MyMoneyMoney(-2000, 100));
1344         QVERIFY(m->totalBalance("A000002", QDate(2002, 1, 15)).isZero());
1345 
1346         QCOMPARE(m->balance("A000001"), MyMoneyMoney(-1000, 100));
1347         QCOMPARE(m->balance("A000002"), MyMoneyMoney(-1000, 100));
1348         // Date of a transaction
1349         QCOMPARE(m->balance("A000001", QDate(2002, 2, 1)), MyMoneyMoney(-1000, 100));
1350         QCOMPARE(m->balance("A000002", QDate(2002, 2, 1)), MyMoneyMoney(-1000, 100));
1351         // Date after last transaction
1352         QCOMPARE(m->balance("A000001", QDate(2002, 2, 1)), MyMoneyMoney(-1000, 100));
1353         QCOMPARE(m->balance("A000002", QDate(2002, 2, 1)), MyMoneyMoney(-1000, 100));
1354         // Date before first transaction
1355         QVERIFY(m->balance("A000001", QDate(2002, 1, 15)).isZero());
1356         QVERIFY(m->balance("A000002", QDate(2002, 1, 15)).isZero());
1357 
1358     } catch (const MyMoneyException &) {
1359         QFAIL("Unexpected exception!");
1360     }
1361 
1362     // Now check for exceptions
1363     try {
1364         // Account not found for balance()
1365         QVERIFY(m->balance("A000005").isZero());
1366         QFAIL("Exception expected");
1367     } catch (const MyMoneyException &) {
1368     }
1369 
1370     try {
1371         // Account not found for totalBalance()
1372         QVERIFY(m->totalBalance("A000005").isZero());
1373         QFAIL("Exception expected");
1374     } catch (const MyMoneyException &) {
1375     }
1376 
1377 }
1378 
1379 void MyMoneyFileTest::testModifyStandardAccountNames()
1380 {
1381     MyMoneyFileTransaction ft;
1382     clearObjectLists();
1383     try {
1384         auto account = m->account(MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Liability));
1385         QVERIFY(account.name() != QLatin1String("Verbindlichkeiten"));
1386         account.setName(QLatin1String("Verbindlichkeiten"));
1387         m->modifyAccount(account);
1388         ft.commit();
1389         QCOMPARE(m_objectsRemoved.count(), 0);
1390         QCOMPARE(m_objectsModified.count(), 1);
1391         QCOMPARE(m_objectsAdded.count(), 0);
1392         QCOMPARE(m_balanceChanged.count(), 0);
1393         QCOMPARE(m_valueChanged.count(), 0);
1394         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Liability")));
1395 
1396     } catch (const MyMoneyException &) {
1397         QFAIL("Unexpected exception");
1398     }
1399     ft.restart();
1400     clearObjectLists();
1401     try {
1402         auto account = m->account(MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Asset));
1403         QVERIFY(account.name() != QString::fromUtf8("Vermögen"));
1404         account.setName(QString::fromUtf8("Vermögen"));
1405         m->modifyAccount(account);
1406         ft.commit();
1407         QCOMPARE(m_objectsRemoved.count(), 0);
1408         QCOMPARE(m_objectsModified.count(), 1);
1409         QCOMPARE(m_objectsAdded.count(), 0);
1410         QCOMPARE(m_balanceChanged.count(), 0);
1411         QCOMPARE(m_valueChanged.count(), 0);
1412         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
1413 
1414     } catch (const MyMoneyException &) {
1415         QFAIL("Unexpected exception");
1416     }
1417     ft.restart();
1418     clearObjectLists();
1419     try {
1420         auto account = m->account(MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Expense));
1421         QVERIFY(account.name() != QLatin1String("Ausgaben"));
1422         account.setName(QLatin1String("Ausgaben"));
1423         m->modifyAccount(account);
1424         ft.commit();
1425         QCOMPARE(m_objectsRemoved.count(), 0);
1426         QCOMPARE(m_objectsModified.count(), 1);
1427         QCOMPARE(m_objectsAdded.count(), 0);
1428         QCOMPARE(m_balanceChanged.count(), 0);
1429         QCOMPARE(m_valueChanged.count(), 0);
1430         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Expense")));
1431 
1432     } catch (const MyMoneyException &) {
1433         QFAIL("Unexpected exception");
1434     }
1435     ft.restart();
1436     clearObjectLists();
1437     try {
1438         auto account = m->account(MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Income));
1439         QVERIFY(account.name() != QLatin1String("Einnahmen"));
1440         account.setName(QLatin1String("Einnahmen"));
1441         m->modifyAccount(account);
1442         ft.commit();
1443         QCOMPARE(m_objectsRemoved.count(), 0);
1444         QCOMPARE(m_objectsModified.count(), 1);
1445         QCOMPARE(m_objectsAdded.count(), 0);
1446         QCOMPARE(m_balanceChanged.count(), 0);
1447         QCOMPARE(m_valueChanged.count(), 0);
1448         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Income")));
1449 
1450     } catch (const MyMoneyException &) {
1451         QFAIL("Unexpected exception");
1452     }
1453     ft.restart();
1454 
1455     QCOMPARE(m->liability().name(), QLatin1String("Verbindlichkeiten"));
1456     QCOMPARE(m->asset().name(), QString::fromUtf8("Vermögen"));
1457     QCOMPARE(m->expense().name(), QLatin1String("Ausgaben"));
1458     QCOMPARE(m->income().name(), QLatin1String("Einnahmen"));
1459 }
1460 
1461 void MyMoneyFileTest::testAddPayee()
1462 {
1463     MyMoneyPayee p;
1464 
1465     p.setName("THB");
1466     QCOMPARE(m->dirty(), false);
1467     MyMoneyFileTransaction ft;
1468     try {
1469         m->addPayee(p);
1470         ft.commit();
1471         QCOMPARE(m->dirty(), true);
1472         QCOMPARE(p.id(), QLatin1String("P000001"));
1473 
1474         QCOMPARE(m_objectsRemoved.count(), 0);
1475         QCOMPARE(m_objectsModified.count(), 0);
1476         QCOMPARE(m_objectsAdded.count(), 1);
1477         QCOMPARE(m_balanceChanged.count(), 0);
1478         QCOMPARE(m_valueChanged.count(), 0);
1479 
1480         QVERIFY(m_objectsAdded.contains(QLatin1String("P000001")));
1481     } catch (const MyMoneyException &) {
1482         QFAIL("Unexpected exception");
1483     }
1484 }
1485 
1486 void MyMoneyFileTest::testModifyPayee()
1487 {
1488     MyMoneyPayee p;
1489 
1490     testAddPayee();
1491     clearObjectLists();
1492 
1493     p = m->payee("P000001");
1494     p.setName("New name");
1495     MyMoneyFileTransaction ft;
1496     try {
1497         m->modifyPayee(p);
1498         ft.commit();
1499         p = m->payee("P000001");
1500         QCOMPARE(p.name(), QLatin1String("New name"));
1501 
1502         QCOMPARE(m_objectsRemoved.count(), 0);
1503         QCOMPARE(m_objectsModified.count(), 1);
1504         QCOMPARE(m_objectsAdded.count(), 0);
1505         QCOMPARE(m_balanceChanged.count(), 0);
1506         QCOMPARE(m_valueChanged.count(), 0);
1507 
1508         QVERIFY(m_objectsModified.contains(QLatin1String("P000001")));
1509     } catch (const MyMoneyException &) {
1510         QFAIL("Unexpected exception");
1511     }
1512 }
1513 
1514 void MyMoneyFileTest::testRemovePayee()
1515 {
1516     MyMoneyPayee p;
1517 
1518     testAddPayee();
1519     clearObjectLists();
1520     QCOMPARE(m->payeeList().count(), 1);
1521 
1522     p = m->payee("P000001");
1523     MyMoneyFileTransaction ft;
1524     try {
1525         m->removePayee(p);
1526         ft.commit();
1527         QCOMPARE(m->payeeList().count(), 0);
1528 
1529         QCOMPARE(m_objectsRemoved.count(), 1);
1530         QCOMPARE(m_objectsModified.count(), 0);
1531         QCOMPARE(m_objectsAdded.count(), 0);
1532         QCOMPARE(m_balanceChanged.count(), 0);
1533         QCOMPARE(m_valueChanged.count(), 0);
1534 
1535         QVERIFY(m_objectsRemoved.contains(QLatin1String("P000001")));
1536 
1537     } catch (const MyMoneyException &) {
1538         QFAIL("Unexpected exception");
1539     }
1540 }
1541 
1542 void MyMoneyFileTest::testPayeeWithIdentifier()
1543 {
1544     MyMoneyPayee p;
1545     try {
1546         MyMoneyFileTransaction ft;
1547         m->addPayee(p);
1548         ft.commit();
1549 
1550         p = m->payee(p.id());
1551 
1552         payeeIdentifier ident = payeeIdentifier(new payeeIdentifiers::ibanBic());
1553         payeeIdentifierTyped<payeeIdentifiers::ibanBic> iban(ident);
1554         iban->setIban(QLatin1String("DE82 2007 0024 0066 6446 00"));
1555 
1556         ft.restart();
1557         p.addPayeeIdentifier(iban);
1558         m->modifyPayee(p);
1559         ft.commit();
1560 
1561         p = m->payee(p.id());
1562         QCOMPARE(p.payeeIdentifiers().count(), 1);
1563 
1564         ident = p.payeeIdentifiers().at(0);
1565         try {
1566             iban = payeeIdentifierTyped<payeeIdentifiers::ibanBic>(ident);
1567         } catch (...) {
1568             QFAIL("Unexpected exception");
1569         }
1570         QCOMPARE(iban->electronicIban(), QLatin1String("DE82200700240066644600"));
1571     } catch (const MyMoneyException &e) {
1572         unexpectedException(e);
1573     }
1574 }
1575 
1576 void MyMoneyFileTest::testAddTransactionStd()
1577 {
1578     testAddAccounts();
1579     MyMoneyTransaction t, p;
1580     MyMoneyAccount a;
1581 
1582     a = m->account("A000001");
1583 
1584     // construct a transaction and add it to the pool
1585     t.setPostDate(QDate(2002, 2, 1));
1586     t.setMemo("Memotext");
1587 
1588     MyMoneySplit split1;
1589     MyMoneySplit split2;
1590 
1591     split1.setAccountId("A000001");
1592     split1.setShares(MyMoneyMoney(-1000, 100));
1593     split1.setValue(MyMoneyMoney(-1000, 100));
1594     split2.setAccountId(MyMoneyAccount::stdAccName(eMyMoney::Account::Standard::Expense));
1595     split2.setValue(MyMoneyMoney(1000, 100));
1596     split2.setShares(MyMoneyMoney(1000, 100));
1597     try {
1598         t.addSplit(split1);
1599         t.addSplit(split2);
1600     } catch (const MyMoneyException &) {
1601         QFAIL("Unexpected exception!");
1602     }
1603 
1604     /*
1605             // FIXME: we don't have a payee and a number field right now
1606             // guess we should have a number field per split, don't know
1607             // about the payee
1608             t.setMethod(MyMoneyCheckingTransaction::Withdrawal);
1609             t.setPayee("Thomas Baumgart");
1610             t.setNumber("1234");
1611             t.setState(MyMoneyCheckingTransaction::Cleared);
1612     */
1613     m->setDirty(false);
1614 
1615     MyMoneyFileTransaction ft;
1616     try {
1617         m->addTransaction(t);
1618         ft.commit();
1619         QFAIL("Missing expected exception!");
1620     } catch (const MyMoneyException &) {
1621     }
1622 
1623     QCOMPARE(m->dirty(), false);
1624 }
1625 
1626 
1627 void MyMoneyFileTest::testAccount2Category()
1628 {
1629     testReparentAccount();
1630     QCOMPARE(m->accountToCategory("A000001"), QLatin1String("Account2:Account1"));
1631     QCOMPARE(m->accountToCategory("A000002"), QLatin1String("Account2"));
1632 }
1633 
1634 void MyMoneyFileTest::testCategory2Account()
1635 {
1636     testAddTransaction();
1637     MyMoneyAccount a = m->account("A000003");
1638     MyMoneyAccount b = m->account("A000004");
1639 
1640     MyMoneyFileTransaction ft;
1641     try {
1642         m->reparentAccount(b, a);
1643         ft.commit();
1644         QCOMPARE(m->categoryToAccount("Expense1"), QLatin1String("A000003"));
1645         QCOMPARE(m->categoryToAccount("Expense1:Expense2"), QLatin1String("A000004"));
1646         QVERIFY(m->categoryToAccount("Acc2").isEmpty());
1647     } catch (const MyMoneyException &e) {
1648         unexpectedException(e);
1649     }
1650 }
1651 
1652 void MyMoneyFileTest::testHasAccount()
1653 {
1654     testAddAccounts();
1655 
1656     MyMoneyAccount a, b;
1657     a.setAccountType(eMyMoney::Account::Type::Checkings);
1658     a.setName("Account3");
1659     b = m->account("A000001");
1660     MyMoneyFileTransaction ft;
1661     try {
1662         m->addAccount(a, b);
1663         ft.commit();
1664         QCOMPARE(m->accountsModel()->itemList().count(), 3);
1665         QCOMPARE(a.parentAccountId(), QLatin1String("A000001"));
1666         QCOMPARE(m->hasAccount("A000001", "Account3"), true);
1667         QCOMPARE(m->hasAccount("A000001", "Account2"), false);
1668         QCOMPARE(m->hasAccount("A000002", "Account3"), false);
1669     } catch (const MyMoneyException &e) {
1670         unexpectedException(e);
1671     }
1672 }
1673 
1674 void MyMoneyFileTest::testAddEquityAccount()
1675 {
1676     MyMoneyAccount i;
1677     i.setName("Investment");
1678     i.setAccountType(eMyMoney::Account::Type::Investment);
1679 
1680     setupBaseCurrency();
1681 
1682     MyMoneyFileTransaction ft;
1683     try {
1684         MyMoneyAccount parent = m->asset();
1685         m->addAccount(i, parent);
1686         ft.commit();
1687     } catch (const MyMoneyException &e) {
1688         unexpectedException(e);
1689     }
1690     // keep a copy for later use
1691     m_inv = i;
1692 
1693     // make sure, that only equity accounts can be children to it
1694     MyMoneyAccount a;
1695     a.setName("Testaccount");
1696     QList<eMyMoney::Account::Type> list;
1697     list << eMyMoney::Account::Type::Checkings;
1698     list << eMyMoney::Account::Type::Savings;
1699     list << eMyMoney::Account::Type::Cash;
1700     list << eMyMoney::Account::Type::CreditCard;
1701     list << eMyMoney::Account::Type::Loan;
1702     list << eMyMoney::Account::Type::CertificateDep;
1703     list << eMyMoney::Account::Type::Investment;
1704     list << eMyMoney::Account::Type::MoneyMarket;
1705     list << eMyMoney::Account::Type::Asset;
1706     list << eMyMoney::Account::Type::Liability;
1707     list << eMyMoney::Account::Type::Currency;
1708     list << eMyMoney::Account::Type::Income;
1709     list << eMyMoney::Account::Type::Expense;
1710     list << eMyMoney::Account::Type::AssetLoan;
1711 
1712     QList<eMyMoney::Account::Type>::Iterator it;
1713     for (it = list.begin(); it != list.end(); ++it) {
1714         a.setAccountType(*it);
1715         ft.restart();
1716         try {
1717             m->addAccount(a, i);
1718             const auto msg = QStringLiteral("Can add non-equity type %1 to investment").arg(static_cast<int>(*it));
1719             QFAIL(msg.toLatin1());
1720         } catch (const MyMoneyException &) {
1721             ft.commit();
1722         }
1723     }
1724     ft.restart();
1725     try {
1726         a.setName("Teststock");
1727         a.setAccountType(eMyMoney::Account::Type::Stock);
1728         m->addAccount(a, i);
1729         ft.commit();
1730     } catch (const MyMoneyException &e) {
1731         unexpectedException(e);
1732     }
1733 }
1734 
1735 void MyMoneyFileTest::testReparentEquity()
1736 {
1737     testAddEquityAccount();
1738     testAddEquityAccount();
1739     MyMoneyAccount parent;
1740 
1741     // check the bad cases
1742     QList<eMyMoney::Account::Type> list;
1743     list << eMyMoney::Account::Type::Checkings;
1744     list << eMyMoney::Account::Type::Savings;
1745     list << eMyMoney::Account::Type::Cash;
1746     list << eMyMoney::Account::Type::CertificateDep;
1747     list << eMyMoney::Account::Type::MoneyMarket;
1748     list << eMyMoney::Account::Type::Asset;
1749     list << eMyMoney::Account::Type::AssetLoan;
1750     list << eMyMoney::Account::Type::Currency;
1751     parent = m->asset();
1752     testReparentEquity(list, parent);
1753 
1754     list.clear();
1755     list << eMyMoney::Account::Type::CreditCard;
1756     list << eMyMoney::Account::Type::Loan;
1757     list << eMyMoney::Account::Type::Liability;
1758     parent = m->liability();
1759     testReparentEquity(list, parent);
1760 
1761     list.clear();
1762     list << eMyMoney::Account::Type::Income;
1763     parent = m->income();
1764     testReparentEquity(list, parent);
1765 
1766     list.clear();
1767     list << eMyMoney::Account::Type::Expense;
1768     parent = m->expense();
1769     testReparentEquity(list, parent);
1770 
1771     // now check the good case
1772     MyMoneyAccount stock = m->account("A000002");
1773     MyMoneyAccount inv = m->account(m_inv.id());
1774     MyMoneyFileTransaction ft;
1775     try {
1776         m->reparentAccount(stock, inv);
1777         ft.commit();
1778     } catch (const MyMoneyException &e) {
1779         unexpectedException(e);
1780     }
1781 }
1782 
1783 void MyMoneyFileTest::testReparentEquity(QList<eMyMoney::Account::Type>& list, MyMoneyAccount& parent)
1784 {
1785     MyMoneyAccount a;
1786     MyMoneyAccount stock = m->account("A000002");
1787 
1788     QList<eMyMoney::Account::Type>::Iterator it;
1789     MyMoneyFileTransaction ft;
1790     for (it = list.begin(); it != list.end(); ++it) {
1791         a.setName(QString("Testaccount %1").arg((int)*it));
1792         a.setAccountType(*it);
1793         try {
1794             m->addAccount(a, parent);
1795             m->reparentAccount(stock, a);
1796             const auto msg = QStringLiteral("Can reparent stock to non-investment type %1 to account").arg(static_cast<int>(*it));
1797             QFAIL(msg.toLatin1());
1798         } catch (const MyMoneyException &) {
1799             ft.commit();
1800         }
1801         ft.restart();
1802     }
1803 }
1804 
1805 void MyMoneyFileTest::testBaseCurrency()
1806 {
1807     MyMoneySecurity base("EUR", "Euro", QChar(0x20ac));
1808     MyMoneySecurity ref;
1809 
1810     // make sure, no base currency is set
1811     try {
1812         ref = m->baseCurrency();
1813         QVERIFY(ref.id().isEmpty());
1814     } catch (const MyMoneyException &e) {
1815         unexpectedException(e);
1816     }
1817 
1818     // make sure, we cannot assign an unknown currency
1819     try {
1820         m->setBaseCurrency(base);
1821         QFAIL("Missing expected exception");
1822     } catch (const MyMoneyException &) {
1823     }
1824 
1825     MyMoneyFileTransaction ft;
1826     // add the currency and try again
1827     try {
1828         m->addCurrency(base);
1829         m->setBaseCurrency(base);
1830         ft.commit();
1831     } catch (const MyMoneyException &e) {
1832         unexpectedException(e);
1833     }
1834     ft.restart();
1835 
1836     // make sure, the base currency is set
1837     try {
1838         ref = m->baseCurrency();
1839         QCOMPARE(ref.id(), QLatin1String("EUR"));
1840         QCOMPARE(ref.name(), QLatin1String("Euro"));
1841         QVERIFY(ref.tradingSymbol().at(0) == QChar(0x20ac));
1842     } catch (const MyMoneyException &e) {
1843         unexpectedException(e);
1844     }
1845 }
1846 
1847 void MyMoneyFileTest::testOpeningBalanceNoBase()
1848 {
1849     MyMoneyAccount openingAcc;
1850     MyMoneySecurity base;
1851 
1852     try {
1853         base = m->baseCurrency();
1854         openingAcc = m->openingBalanceAccount(base);
1855         QFAIL("Missing expected exception");
1856     } catch (const MyMoneyException &) {
1857     }
1858 }
1859 
1860 void MyMoneyFileTest::testOpeningBalance()
1861 {
1862     MyMoneyAccount openingAcc;
1863     MyMoneySecurity second("USD", "US Dollar", "$");
1864     setupBaseCurrency();
1865 
1866     try {
1867         openingAcc = m->openingBalanceAccount(m->baseCurrency());
1868         QCOMPARE(openingAcc.parentAccountId(), m->equity().id());
1869         QCOMPARE(openingAcc.name(), MyMoneyFile::openingBalancesPrefix());
1870         QCOMPARE(openingAcc.openingDate(), QDate::currentDate());
1871     } catch (const MyMoneyException &e) {
1872         unexpectedException(e);
1873     }
1874 
1875     // add a second currency
1876     MyMoneyFileTransaction ft;
1877     try {
1878         m->addCurrency(second);
1879         ft.commit();
1880     } catch (const MyMoneyException &e) {
1881         unexpectedException(e);
1882     }
1883 
1884     QString refName = QString("%1 (%2)").arg(MyMoneyFile::openingBalancesPrefix(), QLatin1String("USD"));
1885     try {
1886         openingAcc = m->openingBalanceAccount(second);
1887         QCOMPARE(openingAcc.parentAccountId(), m->equity().id());
1888         QCOMPARE(openingAcc.name(), refName);
1889         QCOMPARE(openingAcc.openingDate(), QDate::currentDate());
1890     } catch (const MyMoneyException &e) {
1891         unexpectedException(e);
1892     }
1893 }
1894 
1895 void MyMoneyFileTest::testModifyStdAccount()
1896 {
1897     QVERIFY(m->asset().currencyId().isEmpty());
1898     QCOMPARE(m->asset().name(), QLatin1String("Asset accounts"));
1899     setupBaseCurrency();
1900     // testBaseCurrency();
1901     QVERIFY(m->asset().currencyId().isEmpty());
1902     QVERIFY(!m->baseCurrency().id().isEmpty());
1903 
1904     MyMoneyFileTransaction ft;
1905     try {
1906         MyMoneyAccount acc = m->asset();
1907         acc.setName("Anlagen");
1908         acc.setCurrencyId(m->baseCurrency().id());
1909         m->modifyAccount(acc);
1910         ft.commit();
1911 
1912         QCOMPARE(m->asset().name(), QLatin1String("Anlagen"));
1913         QCOMPARE(m->asset().currencyId(), m->baseCurrency().id());
1914     } catch (const MyMoneyException &e) {
1915         unexpectedException(e);
1916     }
1917 
1918     ft.restart();
1919     try {
1920         MyMoneyAccount acc = m->asset();
1921         acc.setNumber("Test");
1922         m->modifyAccount(acc);
1923         QFAIL("Missing expected exception");
1924     } catch (const MyMoneyException &) {
1925         ft.rollback();
1926     }
1927 
1928 }
1929 
1930 void MyMoneyFileTest::testAddPrice()
1931 {
1932     testAddAccounts();
1933     setupBaseCurrency();
1934     MyMoneyAccount p;
1935 
1936     MyMoneyFileTransaction ft;
1937     try {
1938         p = m->account("A000002");
1939         p.setCurrencyId("RON");
1940         m->modifyAccount(p);
1941         ft.commit();
1942 
1943         QCOMPARE(m->account("A000002").currencyId(), QLatin1String("RON"));
1944     } catch (const MyMoneyException &e) {
1945         unexpectedException(e);
1946     }
1947 
1948     clearObjectLists();
1949     ft.restart();
1950     MyMoneyPrice price("EUR", "RON", QDate::currentDate(), MyMoneyMoney(4.1), "Test source");
1951     m->addPrice(price);
1952     ft.commit();
1953     QCOMPARE(m_balanceChanged.count(), 0);
1954     QCOMPARE(m_valueChanged.count(), 1);
1955     QCOMPARE(m_valueChanged.count("A000002"), 1);
1956 
1957     clearObjectLists();
1958     ft.restart();
1959     MyMoneyPrice priceReciprocal("RON", "EUR", QDate::currentDate(), MyMoneyMoney(1 / 4.1), "Test source reciprocal price");
1960     m->addPrice(priceReciprocal);
1961     ft.commit();
1962     QCOMPARE(m_balanceChanged.count(), 0);
1963     QCOMPARE(m_valueChanged.count(), 1);
1964     QCOMPARE(m_valueChanged.count("A000002"), 1);
1965 }
1966 
1967 void MyMoneyFileTest::testRemovePrice()
1968 {
1969     testAddPrice();
1970     clearObjectLists();
1971     MyMoneyFileTransaction ft;
1972     MyMoneyPrice price("EUR", "RON", QDate::currentDate(), MyMoneyMoney(4.1), "Test source");
1973     m->removePrice(price);
1974     ft.commit();
1975     QCOMPARE(m_balanceChanged.count(), 0);
1976     QCOMPARE(m_valueChanged.count(), 1);
1977     QCOMPARE(m_valueChanged.count("A000002"), 1);
1978 }
1979 
1980 void MyMoneyFileTest::testGetPrice()
1981 {
1982     testAddPrice();
1983     // the price for the current date is found
1984     QVERIFY(m->price("EUR", "RON", QDate::currentDate()).isValid());
1985     // the price for the current date is returned when asking for the next day with exact date set to false
1986     {
1987         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(1), false);
1988         QVERIFY(price.isValid() && price.date() == QDate::currentDate());
1989     }
1990     // no price is returned while asking for the next day with exact date set to true
1991     QVERIFY(!m->price("EUR", "RON", QDate::currentDate().addDays(1), true).isValid());
1992 
1993     // no price is returned while asking for the previous day with exact date set to true/false because all prices are newer
1994     QVERIFY(!m->price("EUR", "RON", QDate::currentDate().addDays(-1), false).isValid());
1995     QVERIFY(!m->price("EUR", "RON", QDate::currentDate().addDays(-1), true).isValid());
1996 
1997     // add two more prices
1998     MyMoneyFileTransaction ft;
1999     m->addPrice(MyMoneyPrice("EUR", "RON", QDate::currentDate().addDays(3), MyMoneyMoney(4.1), "Test source"));
2000     m->addPrice(MyMoneyPrice("EUR", "RON", QDate::currentDate().addDays(5), MyMoneyMoney(4.1), "Test source"));
2001     ft.commit();
2002     clearObjectLists();
2003 
2004     // extra tests for the exactDate=false behavior
2005     {
2006         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(2), false);
2007         QVERIFY(price.isValid() && price.date() == QDate::currentDate());
2008     }
2009     {
2010         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(3), false);
2011         QVERIFY(price.isValid() && price.date() == QDate::currentDate().addDays(3));
2012     }
2013     {
2014         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(4), false);
2015         QVERIFY(price.isValid() && price.date() == QDate::currentDate().addDays(3));
2016     }
2017     {
2018         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(5), false);
2019         QVERIFY(price.isValid() && price.date() == QDate::currentDate().addDays(5));
2020     }
2021     {
2022         const MyMoneyPrice &price = m->price("EUR", "RON", QDate::currentDate().addDays(6), false);
2023         QVERIFY(price.isValid() && price.date() == QDate::currentDate().addDays(5));
2024     }
2025 }
2026 
2027 void MyMoneyFileTest::testAddAccountMissingCurrency()
2028 {
2029     testAddTwoInstitutions();
2030     MyMoneySecurity base("EUR", "Euro", QChar(0x20ac));
2031     MyMoneyAccount  a;
2032     a.setAccountType(eMyMoney::Account::Type::Checkings);
2033 
2034     MyMoneyInstitution institution;
2035 
2036     m->setDirty(false);
2037 
2038     QCOMPARE(m->accountsModel()->itemList().count(), 0);
2039 
2040     institution = m->institution("I000001");
2041     QCOMPARE(institution.id(), QLatin1String("I000001"));
2042 
2043     a.setName("Account1");
2044     a.setInstitutionId(institution.id());
2045 
2046     clearObjectLists();
2047     MyMoneyFileTransaction ft;
2048     try {
2049         m->addCurrency(base);
2050         m->setBaseCurrency(base);
2051         MyMoneyAccount parent = m->asset();
2052         m->addAccount(a, parent);
2053         ft.commit();
2054         QCOMPARE(m->account("A000001").currencyId(), QLatin1String("EUR"));
2055     } catch (const MyMoneyException &e) {
2056         unexpectedException(e);
2057     }
2058 }
2059 
2060 void MyMoneyFileTest::testAddTransactionToClosedAccount()
2061 {
2062     QSKIP("Test not implemented yet", SkipAll);
2063 }
2064 
2065 void MyMoneyFileTest::testRemoveTransactionFromClosedAccount()
2066 {
2067     QSKIP("Test not implemented yet", SkipAll);
2068 }
2069 
2070 void MyMoneyFileTest::testModifyTransactionInClosedAccount()
2071 {
2072     QSKIP("Test not implemented yet", SkipAll);
2073 }
2074 
2075 void MyMoneyFileTest::testStorageId()
2076 {
2077     // make sure id will be setup if it does not exist
2078     MyMoneyFileTransaction ft;
2079     try {
2080         m->setValue("kmm-id", "");
2081         ft.commit();
2082     } catch (const MyMoneyException &e) {
2083         unexpectedException(e);
2084     }
2085 
2086     try {
2087         // check for a new id
2088         auto id = m->storageId();
2089         QVERIFY(!id.isNull());
2090         // check that it is the same if we ask again
2091         QCOMPARE(id, m->storageId());
2092     } catch (const MyMoneyException &e) {
2093         unexpectedException(e);
2094     }
2095 }
2096 
2097 void MyMoneyFileTest::testHasMatchingOnlineBalance_emptyAccountWithoutImportedBalance()
2098 {
2099     addOneAccount();
2100 
2101     MyMoneyAccount a = m->account("A000001");
2102 
2103     QCOMPARE(m->hasMatchingOnlineBalance(a), false);
2104 }
2105 
2106 void MyMoneyFileTest::testHasMatchingOnlineBalance_emptyAccountWithEqualImportedBalance()
2107 {
2108     addOneAccount();
2109 
2110     MyMoneyAccount a = m->account("A000001");
2111 
2112     a.setValue("lastImportedTransactionDate", QDate(2011, 12, 1).toString(Qt::ISODate));
2113     a.setValue("lastStatementBalance", MyMoneyMoney().toString());
2114 
2115     MyMoneyFileTransaction ft;
2116     m->modifyAccount(a);
2117     ft.commit();
2118 
2119     QCOMPARE(m->hasMatchingOnlineBalance(a), true);
2120 }
2121 
2122 void MyMoneyFileTest::testHasMatchingOnlineBalance_emptyAccountWithUnequalImportedBalance()
2123 {
2124     addOneAccount();
2125 
2126     MyMoneyAccount a = m->account("A000001");
2127 
2128     a.setValue("lastImportedTransactionDate", QDate(2011, 12, 1).toString(Qt::ISODate));
2129     a.setValue("lastStatementBalance", MyMoneyMoney::ONE.toString());
2130 
2131     MyMoneyFileTransaction ft;
2132     m->modifyAccount(a);
2133     ft.commit();
2134 
2135     QCOMPARE(m->hasMatchingOnlineBalance(a), false);
2136 }
2137 
2138 void MyMoneyFileTest::testHasNewerTransaction_withoutAnyTransaction_afterLastImportedTransaction()
2139 {
2140     addOneAccount();
2141 
2142     MyMoneyAccount a = m->account("A000001");
2143 
2144     QDate dateOfLastTransactionImport(2011, 12, 1);
2145 
2146     // There are no transactions at all:
2147     QCOMPARE(m->hasNewerTransaction(a.id(), dateOfLastTransactionImport), false);
2148 }
2149 
2150 void MyMoneyFileTest::testHasNewerTransaction_withoutNewerTransaction_afterLastImportedTransaction()
2151 {
2152 
2153     addOneAccount();
2154     setupBaseCurrency();
2155 
2156     QString accId("A000001");
2157     QDate dateOfLastTransactionImport(2011, 12, 1);
2158 
2159     MyMoneyFileTransaction ft;
2160     MyMoneyTransaction t;
2161 
2162     // construct a transaction at the day of the last transaction import and add it to the pool
2163     t.setPostDate(dateOfLastTransactionImport);
2164 
2165     MyMoneySplit split1;
2166 
2167     split1.setAccountId(accId);
2168     split1.setShares(MyMoneyMoney(-1000, 100));
2169     split1.setValue(MyMoneyMoney(-1000, 100));
2170     t.addSplit(split1);
2171 
2172     ft.restart();
2173     m->addTransaction(t);
2174     ft.commit();
2175 
2176     QCOMPARE(m->hasNewerTransaction(accId, dateOfLastTransactionImport), false);
2177 }
2178 
2179 void MyMoneyFileTest::testHasNewerTransaction_withNewerTransaction_afterLastImportedTransaction()
2180 {
2181 
2182     addOneAccount();
2183     setupBaseCurrency();
2184 
2185     QString accId("A000001");
2186     QDate dateOfLastTransactionImport(2011, 12, 1);
2187     QDate dateOfDayAfterLastTransactionImport(dateOfLastTransactionImport.addDays(1));
2188 
2189     MyMoneyFileTransaction ft;
2190     MyMoneyTransaction t;
2191 
2192     // construct a transaction a day after the last transaction import and add it to the pool
2193     t.setPostDate(dateOfDayAfterLastTransactionImport);
2194 
2195     MyMoneySplit split1;
2196 
2197     split1.setAccountId(accId);
2198     split1.setShares(MyMoneyMoney(-1000, 100));
2199     split1.setValue(MyMoneyMoney(-1000, 100));
2200     t.addSplit(split1);
2201 
2202     ft.restart();
2203     m->addTransaction(t);
2204     ft.commit();
2205 
2206     QCOMPARE(m->hasNewerTransaction(accId, dateOfLastTransactionImport), true);
2207 }
2208 
2209 void MyMoneyFileTest::addOneAccount()
2210 {
2211     setupBaseCurrency();
2212     QString accountId = "A000001";
2213     MyMoneyAccount  a;
2214     a.setAccountType(eMyMoney::Account::Type::Checkings);
2215 
2216     m->setDirty(false);
2217 
2218     QCOMPARE(m->accountsModel()->itemList().count(), 0);
2219 
2220     a.setName("Account1");
2221     a.setCurrencyId("EUR");
2222 
2223     clearObjectLists();
2224     MyMoneyFileTransaction ft;
2225     try {
2226         MyMoneyAccount parent = m->asset();
2227         m->addAccount(a, parent);
2228         ft.commit();
2229         QCOMPARE(m->accountsModel()->itemList().count(), 1);
2230         QCOMPARE(a.parentAccountId(), QLatin1String("AStd::Asset"));
2231         QCOMPARE(a.id(), accountId);
2232         QCOMPARE(a.currencyId(), QLatin1String("EUR"));
2233         QCOMPARE(m->dirty(), true);
2234         QCOMPARE(m->asset().accountList().count(), 1);
2235         QCOMPARE(m->asset().accountList()[0], accountId);
2236 
2237         QCOMPARE(m_objectsRemoved.count(), 0);
2238         QCOMPARE(m_objectsAdded.count(), 1);
2239         QCOMPARE(m_objectsModified.count(), 1);
2240         QCOMPARE(m_balanceChanged.count(), 0);
2241         QCOMPARE(m_valueChanged.count(), 0);
2242         QVERIFY(m_objectsAdded.contains(accountId.toLatin1()));
2243         QVERIFY(m_objectsModified.contains(QLatin1String("AStd::Asset")));
2244 
2245     } catch (const MyMoneyException &) {
2246         QFAIL("Unexpected exception!");
2247     }
2248 }
2249 
2250 void MyMoneyFileTest::testCountTransactionsWithSpecificReconciliationState_noTransactions()
2251 {
2252     addOneAccount();
2253     QString accountId = "A000001";
2254 
2255     QCOMPARE(m->countTransactionsWithSpecificReconciliationState(accountId, eMyMoney::TransactionFilter::State::NotReconciled), 0);
2256 }
2257 
2258 void MyMoneyFileTest::testCountTransactionsWithSpecificReconciliationState_transactionWithWantedReconcileState()
2259 {
2260     addOneAccount();
2261     setupBaseCurrency();
2262 
2263     QString accountId = "A000001";
2264 
2265     // construct split & transaction
2266     MyMoneySplit split;
2267     split.setAccountId(accountId);
2268     split.setShares(MyMoneyMoney(-1000, 100));
2269     split.setValue(MyMoneyMoney(-1000, 100));
2270 
2271     MyMoneyTransaction transaction;
2272     transaction.setPostDate(QDate(2013, 1, 1));
2273     transaction.addSplit(split);
2274 
2275     // add transaction
2276     MyMoneyFileTransaction ft;
2277     m->addTransaction(transaction);
2278     ft.commit();
2279 
2280     QCOMPARE(m->countTransactionsWithSpecificReconciliationState(accountId, eMyMoney::TransactionFilter::State::NotReconciled), 1);
2281 }
2282 
2283 void MyMoneyFileTest::testCountTransactionsWithSpecificReconciliationState_transactionWithUnwantedReconcileState()
2284 {
2285     addOneAccount();
2286     setupBaseCurrency();
2287 
2288     QString accountId = "A000001";
2289 
2290     // construct split & transaction
2291     MyMoneySplit split;
2292     split.setAccountId(accountId);
2293     split.setShares(MyMoneyMoney(-1000, 100));
2294     split.setValue(MyMoneyMoney(-1000, 100));
2295     split.setReconcileFlag(eMyMoney::Split::State::Reconciled);
2296 
2297     MyMoneyTransaction transaction;
2298     transaction.setPostDate(QDate(2013, 1, 1));
2299     transaction.addSplit(split);
2300 
2301     // add transaction
2302     MyMoneyFileTransaction ft;
2303     m->addTransaction(transaction);
2304     ft.commit();
2305 
2306     QCOMPARE(m->countTransactionsWithSpecificReconciliationState(accountId, eMyMoney::TransactionFilter::State::NotReconciled), 0);
2307 }
2308 
2309 void MyMoneyFileTest::testAddOnlineJob()
2310 {
2311     QSKIP("Need dummy task for this test", SkipAll);
2312 #if 0
2313     // Add a onlineJob
2314     onlineJob job(new germanOnlineTransfer());
2315 
2316     MyMoneyFileTransaction ft;
2317     m->addOnlineJob(job);
2318     QCOMPARE(job.id(), QString("O000001"));
2319     ft.commit();
2320 
2321     QCOMPARE(m_objectsRemoved.count(), 0);
2322     QCOMPARE(m_objectsAdded.count(), 1);
2323     QCOMPARE(m_objectsModified.count(), 0);
2324     QCOMPARE(m_balanceChanged.count(), 0);
2325     QCOMPARE(m_valueChanged.count(), 0);
2326 #endif
2327 }
2328 
2329 void MyMoneyFileTest::testGetOnlineJob()
2330 {
2331     QSKIP("Need dummy task for this test", SkipAll);
2332 #if 0
2333     testAddOnlineJob();
2334 
2335     const onlineJob requestedJob = m->getOnlineJob("O000001");
2336     QVERIFY(!requestedJob.isNull());
2337     QCOMPARE(requestedJob.id(), QString("O000001"));
2338 #endif
2339 }
2340 
2341 void MyMoneyFileTest::testRemoveOnlineJob()
2342 {
2343     QSKIP("Need dummy task for this test", SkipAll);
2344 #if 0
2345     // Add a onlineJob
2346     onlineJob job(new germanOnlineTransfer());
2347     onlineJob job2(new germanOnlineTransfer());
2348     onlineJob job3(new germanOnlineTransfer());
2349 
2350 
2351     MyMoneyFileTransaction ft;
2352     m->addOnlineJob(job);
2353     m->addOnlineJob(job2);
2354     m->addOnlineJob(job3);
2355     ft.commit();
2356 
2357     clearObjectLists();
2358 
2359     ft.restart();
2360     m->removeOnlineJob(job);
2361     m->removeOnlineJob(job2);
2362     ft.commit();
2363 
2364     QCOMPARE(m_objectsRemoved.count(), 2);
2365     QCOMPARE(m_objectsAdded.count(), 0);
2366     QCOMPARE(m_objectsModified.count(), 0);
2367     QCOMPARE(m_balanceChanged.count(), 0);
2368     QCOMPARE(m_valueChanged.count(), 0);
2369 #endif
2370 }
2371 
2372 void MyMoneyFileTest::testOnlineJobRollback()
2373 {
2374     QSKIP("Need dummy task for this test", SkipAll);
2375 #if 0
2376     // Add a onlineJob
2377     onlineJob job(new germanOnlineTransfer());
2378     onlineJob job2(new germanOnlineTransfer());
2379     onlineJob job3(new germanOnlineTransfer());
2380 
2381     MyMoneyFileTransaction ft;
2382     m->addOnlineJob(job);
2383     m->addOnlineJob(job2);
2384     m->addOnlineJob(job3);
2385     ft.rollback();
2386 
2387     QCOMPARE(m_objectsRemoved.count(), 0);
2388     QCOMPARE(m_objectsAdded.count(), 0);
2389     QCOMPARE(m_objectsModified.count(), 0);
2390     QCOMPARE(m_balanceChanged.count(), 0);
2391     QCOMPARE(m_valueChanged.count(), 0);
2392 #endif
2393 }
2394 
2395 void MyMoneyFileTest::testRemoveLockedOnlineJob()
2396 {
2397     QSKIP("Need dummy task for this test", SkipAll);
2398 #if 0
2399     // Add a onlineJob
2400     onlineJob job(new germanOnlineTransfer());
2401     job.setLock(true);
2402     QVERIFY(job.isLocked());
2403 
2404     MyMoneyFileTransaction ft;
2405     m->addOnlineJob(job);
2406     ft.commit();
2407 
2408     clearObjectLists();
2409 
2410     // Try removing locked transfer
2411     ft.restart();
2412     m->removeOnlineJob(job);
2413     ft.commit();
2414     QVERIFY2(m_objectsRemoved.count() == 0, "Online Job was locked, removing is not allowed");
2415     QVERIFY(m_objectsAdded.count() == 0);
2416     QVERIFY(m_objectsModified.count() == 0);
2417     QVERIFY(m_balanceChanged.count() == 0);
2418     QVERIFY(m_valueChanged.count() == 0);
2419 
2420 #endif
2421 }
2422 
2423 /** @todo */
2424 void MyMoneyFileTest::testModifyOnlineJob()
2425 {
2426     QSKIP("Need dummy task for this test", SkipAll);
2427 #if 0
2428     // Add a onlineJob
2429     onlineJob job(new germanOnlineTransfer());
2430     MyMoneyFileTransaction ft;
2431     m->addOnlineJob(job);
2432     ft.commit();
2433 
2434     clearObjectLists();
2435 
2436     // Modify online job
2437     job.setJobSend();
2438     ft.restart();
2439     m->modifyOnlineJob(job);
2440     ft.commit();
2441 
2442     QCOMPARE(m_objectsRemoved.count(), 0);
2443     QCOMPARE(m_objectsAdded.count(), 0);
2444     QCOMPARE(m_objectsModified.count(), 1);
2445     QCOMPARE(m_balanceChanged.count(), 0);
2446     QCOMPARE(m_valueChanged.count(), 0);
2447 
2448     //onlineJob modifiedJob = m->getOnlineJob( job.id() );
2449     //QCOMPARE(modifiedJob.responsibleAccount(), QString("Std::Assert"));
2450 #endif
2451 }
2452 
2453 void MyMoneyFileTest::testClearedBalance()
2454 {
2455     testAddTransaction();
2456     MyMoneyTransaction t1;
2457     MyMoneyTransaction t2;
2458 
2459     // construct a transaction and add it to the pool
2460     t1.setPostDate(QDate(2002, 2, 1));
2461     t1.setMemo("Memotext");
2462 
2463     t2.setPostDate(QDate(2002, 2, 4));
2464     t2.setMemo("Memotext");
2465 
2466     MyMoneySplit split1;
2467     MyMoneySplit split2;
2468     MyMoneySplit split3;
2469     MyMoneySplit split4;
2470 
2471     MyMoneyFileTransaction ft;
2472     try {
2473         split1.setAccountId("A000002");
2474         split1.setShares(MyMoneyMoney(-1000, 100));
2475         split1.setValue(MyMoneyMoney(-1000, 100));
2476         split1.setReconcileFlag(eMyMoney::Split::State::Cleared);
2477         split2.setAccountId("A000004");
2478         split2.setValue(MyMoneyMoney(1000, 100));
2479         split2.setShares(MyMoneyMoney(1000, 100));
2480         split2.setReconcileFlag(eMyMoney::Split::State::Cleared);
2481         t1.addSplit(split1);
2482         t1.addSplit(split2);
2483         m->addTransaction(t1);
2484         ft.commit();
2485         ft.restart();
2486         QCOMPARE(t1.id(), QLatin1String("T000000000000000002"));
2487         split3.setAccountId("A000002");
2488         split3.setShares(MyMoneyMoney(-2000, 100));
2489         split3.setValue(MyMoneyMoney(-2000, 100));
2490         split3.setReconcileFlag(eMyMoney::Split::State::Cleared);
2491         split4.setAccountId("A000004");
2492         split4.setValue(MyMoneyMoney(2000, 100));
2493         split4.setShares(MyMoneyMoney(2000, 100));
2494         split4.setReconcileFlag(eMyMoney::Split::State::Cleared);
2495         t2.addSplit(split3);
2496         t2.addSplit(split4);
2497         m->addTransaction(t2);
2498         ft.commit();
2499         ft.restart();
2500 
2501         QCOMPARE(m->balance("A000001", QDate(2002, 2, 4)), MyMoneyMoney(-1000, 100));
2502         QCOMPARE(m->balance("A000002", QDate(2002, 2, 4)), MyMoneyMoney(-3000, 100));
2503         // Date of last cleared transaction
2504         QCOMPARE(m->clearedBalance("A000002", QDate(2002, 2, 1)), MyMoneyMoney(-1000, 100));
2505 
2506         // Date of last transaction
2507         QCOMPARE(m->balance("A000002", QDate(2002, 2, 4)), MyMoneyMoney(-3000, 100));
2508 
2509         // Date before first transaction
2510         QVERIFY(m->clearedBalance("A000002", QDate(2002, 1, 15)).isZero());
2511 
2512 
2513     } catch (const MyMoneyException &) {
2514         QFAIL("Unexpected exception!");
2515     }
2516 }
2517 
2518 void MyMoneyFileTest::testAdjustedValues()
2519 {
2520     // create a checking account, an expense, an investment account and a stock
2521     addOneAccount();
2522 
2523     MyMoneyAccount exp1;
2524     exp1.setAccountType(eMyMoney::Account::Type::Expense);
2525     exp1.setName("Expense1");
2526     exp1.setCurrencyId("EUR");
2527 
2528     MyMoneyFileTransaction ft;
2529     try {
2530         MyMoneyAccount parent = m->expense();
2531         m->addAccount(exp1, parent);
2532         ft.commit();
2533     } catch (const MyMoneyException &) {
2534         QFAIL("Unexpected exception!");
2535     }
2536 
2537     testAddEquityAccount();
2538 
2539     MyMoneySecurity stockSecurity(QLatin1String("Blubber"), QLatin1String("TestStockSecurity"), QLatin1String("BLUB"), 1000, 1000, 1000);
2540     stockSecurity.setTradingCurrency(QLatin1String("BLUB"));
2541     MyMoneySecurity tradingCurrency("BLUB", "BlubCurrency");
2542 
2543     // add the security
2544     ft.restart();
2545     try {
2546         m->addCurrency(tradingCurrency);
2547         m->addSecurity(stockSecurity);
2548         ft.commit();
2549     } catch (const MyMoneyException &e) {
2550         unexpectedException(e);
2551     }
2552 
2553     MyMoneyAccount i = m->accountByName("Investment");
2554     MyMoneyAccount stock;
2555     ft.restart();
2556     try {
2557         stock.setName("Teststock");
2558         stock.setCurrencyId(stockSecurity.id());
2559         stock.setAccountType(eMyMoney::Account::Type::Stock);
2560         m->addAccount(stock, i);
2561         ft.commit();
2562     } catch (const MyMoneyException &e) {
2563         unexpectedException(e);
2564     }
2565 
2566     // values taken from real example on https://bugs.kde.org/show_bug.cgi?id=345655
2567     MyMoneySplit s1, s2, s3;
2568     s1.setAccountId(QLatin1String("A000001"));
2569     s1.setShares(MyMoneyMoney(QLatin1String("-99901/1000")));
2570     s1.setValue(MyMoneyMoney(QLatin1String("-999/10")));
2571 
2572     s2.setAccountId(exp1.id());
2573     s2.setShares(MyMoneyMoney(QLatin1String("-611/250")));
2574     s2.setValue(MyMoneyMoney(QLatin1String("-61/25")));
2575 
2576     s3.setAccountId(stock.id());
2577     s3.setAction(eMyMoney::Split::InvestmentTransactionType::BuyShares);
2578     s3.setShares(MyMoneyMoney(QLatin1String("64901/100000")));
2579     s3.setPrice(MyMoneyMoney(QLatin1String("157689/1000")));
2580     s3.setValue(MyMoneyMoney(QLatin1String("102340161/1000000")));
2581 
2582     MyMoneyTransaction t;
2583     t.setCommodity(QLatin1String("EUR"));
2584     t.setPostDate(QDate::currentDate());
2585     t.addSplit(s1);
2586     t.addSplit(s2);
2587     t.addSplit(s3);
2588 
2589     // make sure the split sum is not zero
2590     QVERIFY(!t.splitSum().isZero());
2591 
2592     ft.restart();
2593     try {
2594         m->addTransaction(t);
2595         ft.commit();
2596     } catch (const MyMoneyException &) {
2597         QFAIL("Unexpected exception!");
2598     }
2599 
2600     QCOMPARE(t.splitById(s1.id()).shares(), MyMoneyMoney(QLatin1String("-999/10")));
2601     QCOMPARE(t.splitById(s1.id()).value(), MyMoneyMoney(QLatin1String("-999/10")));
2602 
2603     QCOMPARE(t.splitById(s2.id()).shares(), MyMoneyMoney(QLatin1String("-61/25")));
2604     QCOMPARE(t.splitById(s2.id()).value(), MyMoneyMoney(QLatin1String("-61/25")));
2605 
2606     QCOMPARE(t.splitById(s3.id()).shares(), MyMoneyMoney(QLatin1String("649/1000")));
2607     QCOMPARE(t.splitById(s3.id()).value(), MyMoneyMoney(QLatin1String("10234/100")));
2608     QCOMPARE(t.splitById(s3.id()).price(), MyMoneyMoney(QLatin1String("157689/1000")));
2609     QCOMPARE(t.splitSum(), MyMoneyMoney());
2610 
2611     // now reset and check if modify also works
2612     s1.setShares(MyMoneyMoney(QLatin1String("-999/10")));
2613     s1.setValue(MyMoneyMoney(QLatin1String("-999/10")));
2614 
2615     s2.setShares(MyMoneyMoney(QLatin1String("-61/25")));
2616     s2.setValue(MyMoneyMoney(QLatin1String("-61/25")));
2617 
2618     s3.setShares(MyMoneyMoney(QLatin1String("649/1000")));
2619     s3.setPrice(MyMoneyMoney(QLatin1String("157689/1000")));
2620     s3.setValue(MyMoneyMoney(QLatin1String("102340161/1000000")));
2621 
2622     t.modifySplit(s1);
2623     t.modifySplit(s2);
2624     t.modifySplit(s3);
2625 
2626     // make sure the split sum is not zero
2627     QVERIFY(!t.splitSum().isZero());
2628 
2629     ft.restart();
2630     try {
2631         m->modifyTransaction(t);
2632         ft.commit();
2633     } catch (const MyMoneyException &) {
2634         QFAIL("Unexpected exception!");
2635     }
2636 
2637     // we need to get the transaction from the engine, as modifyTransaction does
2638     // not return the modified values
2639     MyMoneyTransaction t2 = m->transaction(t.id());
2640 
2641     QCOMPARE(t2.splitById(s3.id()).shares(), MyMoneyMoney(QLatin1String("649/1000")));
2642     QCOMPARE(t2.splitById(s3.id()).value(), MyMoneyMoney(QLatin1String("10234/100")));
2643     QCOMPARE(t2.splitById(s3.id()).price(), MyMoneyMoney(QLatin1String("157689/1000")));
2644     QCOMPARE(t2.splitSum(), MyMoneyMoney());
2645 }
2646 
2647 void MyMoneyFileTest::testVatAssignment()
2648 {
2649     MyMoneyAccount acc;
2650     MyMoneyAccount vat;
2651     MyMoneyAccount expense;
2652 
2653     testAddTransaction();
2654 
2655     vat.setName("VAT");
2656     vat.setCurrencyId("EUR");
2657     vat.setAccountType(eMyMoney::Account::Type::Expense);
2658     // make it a VAT account
2659     vat.setValue(QLatin1String("VatRate"), QLatin1String("20/100"));
2660 
2661     MyMoneyFileTransaction ft;
2662     try {
2663         MyMoneyAccount parent = m->expense();
2664         m->addAccount(vat, parent);
2665         QVERIFY(!vat.id().isEmpty());
2666         acc = m->account(QLatin1String("A000001"));
2667         expense = m->account(QLatin1String("A000003"));
2668         QCOMPARE(acc.name(), QLatin1String("Account1"));
2669         QCOMPARE(expense.name(), QLatin1String("Expense1"));
2670         expense.setValue(QLatin1String("VatAccount"), vat.id());
2671         m->modifyAccount(expense);
2672         ft.commit();
2673     } catch (const MyMoneyException &) {
2674         QFAIL("Unexpected exception!");
2675     }
2676 
2677     // the categories are setup now for gross value entry
2678     MyMoneyTransaction tr;
2679     MyMoneySplit sp;
2680     MyMoneyMoney amount(1707, 100);
2681 
2682     // setup the transaction
2683     sp.setShares(amount);
2684     sp.setValue(amount);
2685     sp.setAccountId(acc.id());
2686     tr.addSplit(sp);
2687     sp.clearId();
2688     sp.setShares(-amount);
2689     sp.setValue(-amount);
2690     sp.setAccountId(expense.id());
2691     tr.addSplit(sp);
2692 
2693     QCOMPARE(m->addVATSplit(tr, acc, expense, amount), true);
2694     QCOMPARE(tr.splits().count(), 3);
2695     QCOMPARE(tr.splitByAccount(acc.id()).shares().toString(), MyMoneyMoney(1707, 100).toString());
2696     QCOMPARE(tr.splitByAccount(expense.id()).shares().toString(), MyMoneyMoney(-1422, 100).toString());
2697     QCOMPARE(tr.splitByAccount(vat.id()).shares().toString(), MyMoneyMoney(-285, 100).toString());
2698     QCOMPARE(tr.splitSum().toString(), MyMoneyMoney().toString());
2699 
2700     tr.removeSplits();
2701     ft.restart();
2702     try {
2703         expense.setValue(QLatin1String("VatAmount"), QLatin1String("net"));
2704         m->modifyAccount(expense);
2705         ft.commit();
2706     } catch (const MyMoneyException &) {
2707         QFAIL("Unexpected exception!");
2708     }
2709 
2710     // the categories are setup now for net value entry
2711     amount = MyMoneyMoney(1422, 100);
2712     sp.clearId();
2713     sp.setShares(amount);
2714     sp.setValue(amount);
2715     sp.setAccountId(acc.id());
2716     tr.addSplit(sp);
2717     sp.clearId();
2718     sp.setShares(-amount);
2719     sp.setValue(-amount);
2720     sp.setAccountId(expense.id());
2721     tr.addSplit(sp);
2722 
2723     QCOMPARE(m->addVATSplit(tr, acc, expense, amount), true);
2724     QCOMPARE(tr.splits().count(), 3);
2725     QCOMPARE(tr.splitByAccount(acc.id()).shares().toString(), MyMoneyMoney(1706, 100).toString());
2726     QCOMPARE(tr.splitByAccount(expense.id()).shares().toString(), MyMoneyMoney(-1422, 100).toString());
2727     QCOMPARE(tr.splitByAccount(vat.id()).shares().toString(), MyMoneyMoney(-284, 100).toString());
2728     QCOMPARE(tr.splitSum().toString(), MyMoneyMoney().toString());
2729 }
2730 
2731 void MyMoneyFileTest::testEmptyFilter()
2732 {
2733     testAddTransaction();
2734 
2735     try {
2736         QList<QPair<MyMoneyTransaction, MyMoneySplit> > tList;
2737         MyMoneyTransactionFilter filter;
2738         MyMoneyFile::instance()->transactionList(tList, filter);
2739         QCOMPARE(tList.count(), 2);
2740 
2741     } catch (const MyMoneyException &) {
2742         QFAIL("Unexpected exception!");
2743     }
2744 }
2745 
2746 void MyMoneyFileTest::testAddSecurity()
2747 {
2748     // create a checking account, an expense, an investment account and a stock
2749     addOneAccount();
2750 
2751     MyMoneyAccount exp1;
2752     exp1.setAccountType(eMyMoney::Account::Type::Expense);
2753     exp1.setName("Expense1");
2754     exp1.setCurrencyId("EUR");
2755 
2756     MyMoneyFileTransaction ft;
2757     try {
2758         MyMoneyAccount parent = m->expense();
2759         m->addAccount(exp1, parent);
2760         ft.commit();
2761     } catch (const MyMoneyException &) {
2762         QFAIL("Unexpected exception!");
2763     }
2764 
2765     testAddEquityAccount();
2766 
2767     MyMoneySecurity stockSecurity(QLatin1String("Blubber"), QLatin1String("TestsockSecurity"), QLatin1String("BLUB"), 1000, 1000, 1000);
2768     stockSecurity.setTradingCurrency(QLatin1String("BLUB"));
2769     // add the security
2770     ft.restart();
2771     try {
2772         m->addSecurity(stockSecurity);
2773         ft.commit();
2774     } catch (const MyMoneyException &e) {
2775         unexpectedException(e);
2776     }
2777 
2778     // check that we can get it via the security method
2779     try {
2780         MyMoneySecurity sec = m->security(stockSecurity.id());
2781     } catch (const MyMoneyException &e) {
2782         unexpectedException(e);
2783     }
2784 
2785     // and also via the currency method
2786     try {
2787         MyMoneySecurity sec = m->currency(stockSecurity.id());
2788     } catch (const MyMoneyException &e) {
2789         unexpectedException(e);
2790     }
2791 }