1 /*
2  * Copyright 2002-2019  Thomas Baumgart <tbaumgart@kde.org>
3  * Copyright 2003       Michael Edwardes <mte@users.sourceforge.net>
4  * Copyright 2004-2006  Ace Jones <acejones@users.sourceforge.net>
5  * Copyright 2004       Kevin Tambascio <ktambascio@users.sourceforge.net>
6  * Copyright 2009-2014  Cristian Oneț <onet.cristian@gmail.com>
7  * Copyright 2012       Alessandro Russo <axela74@yahoo.it>
8  * Copyright 2016       Christian Dávid <christian-david@web.de>
9  * Copyright 2018       Łukasz Wojniłowicz <lukasz.wojnilowicz@gmail.com>
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License as
13  * published by the Free Software Foundation; either version 2 of
14  * the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23  */
24 
25 #include "mymoneyxmlcontenthandler-test.h"
26 
27 #include <QtTest>
28 #include "../mymoneystoragexml.cpp"
29 #include "mymoneyobject_p.h"
30 #include "mymoneyobject.h"
31 #include "mymoneyexception.h"
32 
33 QTEST_GUILESS_MAIN(MyMoneyXmlContentHandlerTest)
34 
35 class TestMyMoneyObjectPrivate : public MyMoneyObjectPrivate
36 {
37 };
38 
39 class TestMyMoneyObject : public MyMoneyObject
40 {
41   Q_DECLARE_PRIVATE(TestMyMoneyObject)
42 
43 public:
TestMyMoneyObject()44   TestMyMoneyObject() : MyMoneyObject(*new MyMoneyObjectPrivate) {}
TestMyMoneyObject(const QString & id)45   TestMyMoneyObject(const QString &id) :
46     MyMoneyObject(*new MyMoneyObjectPrivate, id)
47   {
48   }
49 
TestMyMoneyObject(const TestMyMoneyObject & other)50   TestMyMoneyObject(const TestMyMoneyObject &other) :
51     MyMoneyObject(*new MyMoneyObjectPrivate(*other.d_func()), other.id())
52   {
53   }
54 
TestMyMoneyObject(TestMyMoneyObject && other)55   TestMyMoneyObject(TestMyMoneyObject &&other) : TestMyMoneyObject()
56   {
57     swap(*this, other);
58   }
59 
60   TestMyMoneyObject & operator=(TestMyMoneyObject other);
61   friend void swap(TestMyMoneyObject& first, TestMyMoneyObject& second);
~TestMyMoneyObject()62   ~TestMyMoneyObject() final override
63   {
64   }
65 
hasReferenceTo(const QString &) const66   bool hasReferenceTo(const QString&) const final override
67   {
68     return false;
69   }
70 
readBaseXML(const QDomElement & node,bool forceId=true)71   static TestMyMoneyObject readBaseXML(const QDomElement &node, bool forceId = true)
72   {
73     TestMyMoneyObject obj(node.attribute(QStringLiteral("id")));
74     if (obj.id().isEmpty() && forceId)
75       throw MYMONEYEXCEPTION_CSTRING("Node has no ID");
76     return obj;
77   }
78 };
79 
swap(TestMyMoneyObject & first,TestMyMoneyObject & second)80 void swap(TestMyMoneyObject& first, TestMyMoneyObject& second)
81 {
82   using std::swap;
83   swap(first.d_ptr, second.d_ptr);
84 }
85 
operator =(TestMyMoneyObject other)86 TestMyMoneyObject & TestMyMoneyObject::operator=(TestMyMoneyObject other)
87 {
88   swap(*this, other);
89   return *this;
90 }
91 
92 
readMyMoneyObject()93 void MyMoneyXmlContentHandlerTest::readMyMoneyObject()
94 {
95   TestMyMoneyObject t;
96 
97   QString ref_ok = QString(
98                      "<!DOCTYPE TEST>\n"
99                      "<TRANSACTION-CONTAINER>\n"
100                      " <MYMONEYOBJECT id=\"T000000000000000001\" >\n"
101                      " </MYMONEYOBJECT>\n"
102                      "</TRANSACTION-CONTAINER>\n"
103                    );
104 
105   QString ref_false1 = QString(
106                          "<!DOCTYPE TEST>\n"
107                          "<TRANSACTION-CONTAINER>\n"
108                          " <MYMONEYOBJECT id=\"\" >\n"
109                          " </MYMONEYOBJECT>\n"
110                          "</TRANSACTION-CONTAINER>\n"
111                        );
112 
113   QString ref_false2 = QString(
114                          "<!DOCTYPE TEST>\n"
115                          "<TRANSACTION-CONTAINER>\n"
116                          " <MYMONEYOBJECT >\n"
117                          " </MYMONEYOBJECT>\n"
118                          "</TRANSACTION-CONTAINER>\n"
119                        );
120 
121   QDomDocument doc;
122   QDomElement node;
123 
124   // id="" but required
125   doc.setContent(ref_false1);
126   node = doc.documentElement().firstChild().toElement();
127 
128   try {
129     t = TestMyMoneyObject::readBaseXML(node);
130     QFAIL("Missing expected exception");
131   } catch (const MyMoneyException &) {
132   }
133 
134   // id attribute missing but required
135   doc.setContent(ref_false2);
136   node = doc.documentElement().firstChild().toElement();
137 
138   try {
139     t = TestMyMoneyObject::readBaseXML(node);
140     QFAIL("Missing expected exception");
141   } catch (const MyMoneyException &) {
142   }
143 
144   // id present
145   doc.setContent(ref_ok);
146   node = doc.documentElement().firstChild().toElement();
147 
148   try {
149     t = TestMyMoneyObject::readBaseXML(node);
150     QVERIFY(t.id() == "T000000000000000001");
151   } catch (const MyMoneyException &) {
152     QFAIL("Unexpected exception");
153   }
154 
155   // id="" but not required
156   doc.setContent(ref_false1);
157   node = doc.documentElement().firstChild().toElement();
158 
159   try {
160     t = TestMyMoneyObject::readBaseXML(node, false);
161     QVERIFY(t.id().isEmpty());
162   } catch (const MyMoneyException &) {
163     QFAIL("Unexpected exception");
164   }
165 }
166 
readKeyValueContainer()167 void MyMoneyXmlContentHandlerTest::readKeyValueContainer()
168 {
169   MyMoneyKeyValueContainer kvp;
170   kvp.setValue("Key", "Value");
171   kvp.setValue("key", "value");
172 
173   QString ref_ok(
174     "<!DOCTYPE TEST>\n"
175     "<KVP-CONTAINER>\n"
176     " <KEYVALUEPAIRS>\n"
177     "  <PAIR key=\"key\" value=\"Value\" />\n"
178     "  <PAIR key=\"Key\" value=\"value\" />\n"
179     " </KEYVALUEPAIRS>\n"
180     "</KVP-CONTAINER>\n");
181 
182   QString ref_false(
183     "<!DOCTYPE TEST>\n"
184     "<KVP-CONTAINER>\n"
185     " <KEYVALUE-PAIRS>\n"
186     "  <PAIR key=\"key\" value=\"Value\" />\n"
187     "  <PAIR key=\"Key\" value=\"value\" />\n"
188     " </KEYVALUE-PAIRS>\n"
189     "</KVP-CONTAINER>\n");
190 
191 
192   QDomDocument doc;
193   QDomElement node;
194   doc.setContent(ref_false);
195   node = doc.documentElement().firstChild().toElement();
196 
197   // make sure, an empty node does not trigger an exception
198   try {
199     QDomElement e;
200     MyMoneyKeyValueContainer k;
201     MyMoneyXmlContentHandler::addToKeyValueContainer(k, e);
202   } catch (const MyMoneyException &) {
203     QFAIL("Unexpected exception");
204   }
205 
206   try {
207     MyMoneyKeyValueContainer k;
208     MyMoneyXmlContentHandler::addToKeyValueContainer(k, node);
209     QFAIL("Missing expected exception");
210   } catch (const MyMoneyException &) {
211   }
212 
213   doc.setContent(ref_ok);
214   node = doc.documentElement().firstChild().toElement();
215   try {
216     MyMoneyKeyValueContainer k;
217     MyMoneyXmlContentHandler::addToKeyValueContainer(k, node);
218 //    QVERIFY(k.d_func()->m_kvp.count() == 2); to be enabled soon
219     QVERIFY(k.value("key") == "Value");
220     QVERIFY(k.value("Key") == "value");
221   } catch (const MyMoneyException &) {
222     QFAIL("Unexpected exception");
223   }
224 }
225 
writeKeyValueContainer()226 void MyMoneyXmlContentHandlerTest::writeKeyValueContainer()
227 {
228   MyMoneyKeyValueContainer kvp;
229   kvp.setValue("Key", "Value");
230   kvp.setValue("key", "value");
231 
232   QDomDocument doc("TEST");
233   QDomElement el = doc.createElement("KVP-CONTAINER");
234   doc.appendChild(el);
235   MyMoneyXmlContentHandler::writeKeyValueContainer(kvp, doc, el);
236 
237   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
238   QDomElement kvpContainer = doc.documentElement();
239   QCOMPARE(kvpContainer.tagName(), QLatin1String("KVP-CONTAINER"));
240   QCOMPARE(kvpContainer.childNodes().size(), 1);
241 
242   QVERIFY(kvpContainer.childNodes().at(0).isElement());
243   QDomElement keyValuePairs = kvpContainer.childNodes().at(0).toElement();
244   QCOMPARE(keyValuePairs.tagName(), QLatin1String("KEYVALUEPAIRS"));
245   QCOMPARE(keyValuePairs.childNodes().size(), 2);
246 
247   QVERIFY(keyValuePairs.childNodes().at(0).isElement());
248   QDomElement keyValuePair1 = keyValuePairs.childNodes().at(0).toElement();
249   QCOMPARE(keyValuePair1.tagName(), QLatin1String("PAIR"));
250   QCOMPARE(keyValuePair1.attribute("key"), QLatin1String("Key"));
251   QCOMPARE(keyValuePair1.attribute("value"), QLatin1String("Value"));
252   QCOMPARE(keyValuePair1.childNodes().size(), 0);
253 
254   QVERIFY(keyValuePairs.childNodes().at(1).isElement());
255   QDomElement keyValuePair2 = keyValuePairs.childNodes().at(1).toElement();
256   QCOMPARE(keyValuePair2.tagName(), QLatin1String("PAIR"));
257   QCOMPARE(keyValuePair2.attribute("key"), QLatin1String("key"));
258   QCOMPARE(keyValuePair2.attribute("value"), QLatin1String("value"));
259   QCOMPARE(keyValuePair2.childNodes().size(), 0);
260 }
261 
readTransaction()262 void MyMoneyXmlContentHandlerTest::readTransaction()
263 {
264   MyMoneyTransaction t;
265 
266   QString ref_ok = QString(
267                      "<!DOCTYPE TEST>\n"
268                      "<TRANSACTION-CONTAINER>\n"
269                      " <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"T000000000000000001\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
270                      "  <SPLITS>\n"
271                      "   <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Withdrawal\" bankid=\"SPID\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
272                      "   <TAG id=\"G000001\"/>\n"
273                      "  </SPLITS>\n"
274                      "  <KEYVALUEPAIRS>\n"
275                      "   <PAIR key=\"key\" value=\"value\" />\n"
276                      "  </KEYVALUEPAIRS>\n"
277                      " </TRANSACTION>\n"
278                      "</TRANSACTION-CONTAINER>\n"
279                    );
280 
281   QString ref_false = QString(
282                         "<!DOCTYPE TEST>\n"
283                         "<TRANSACTION-CONTAINER>\n"
284                         " <TRANS-ACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"T000000000000000001\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
285                         "  <SPLITS>\n"
286                         "   <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Withdrawal\" bankid=\"SPID\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
287                         "  </SPLITS>\n"
288                         "  <KEYVALUEPAIRS>\n"
289                         "   <PAIR key=\"key\" value=\"value\" />\n"
290                         "  </KEYVALUEPAIRS>\n"
291                         " </TRANS-ACTION>\n"
292                         "</TRANSACTION-CONTAINER>\n"
293                       );
294 
295   QDomDocument doc;
296   QDomElement node;
297   doc.setContent(ref_false);
298   node = doc.documentElement().firstChild().toElement();
299 
300   try {
301     t = MyMoneyXmlContentHandler::readTransaction(node);
302     QFAIL("Missing expected exception");
303   } catch (const MyMoneyException &) {
304   }
305 
306   doc.setContent(ref_ok);
307   node = doc.documentElement().firstChild().toElement();
308 
309   t.setValue("key", "VALUE");
310   try {
311     t = MyMoneyXmlContentHandler::readTransaction(node);
312     QVERIFY(t.postDate() == QDate(2001, 12, 28));
313     QVERIFY(t.entryDate() == QDate(2003, 9, 29));
314     QVERIFY(t.id() == "T000000000000000001");
315     QVERIFY(t.memo() == "Wohnung:Miete");
316     QVERIFY(t.commodity() == "EUR");
317     QVERIFY(t.pairs().count() == 1);
318     QVERIFY(t.value("key") == "value");
319     QVERIFY(t.splits().count() == 1);
320   } catch (const MyMoneyException &) {
321     QFAIL("Unexpected exception");
322   }
323 }
324 
readTransactionEx()325 void MyMoneyXmlContentHandlerTest::readTransactionEx()
326 {
327   MyMoneyTransaction t;
328 
329   QString ref_ok = QString(
330                      "<!DOCTYPE TEST>\n"
331                      "<TRANSACTION-CONTAINER>\n"
332                      "<TRANSACTION postdate=\"2010-03-05\" memo=\"\" id=\"T000000000000004189\" commodity=\"EUR\" entrydate=\"2010-03-08\" >\n"
333                      " <SPLITS>\n"
334                      "  <SPLIT payee=\"P000010\" reconciledate=\"\" shares=\"-125000/100\" action=\"Transfer\" bankid=\"A000076-2010-03-05-b6850c0-1\" number=\"\" reconcileflag=\"1\" memo=\"UMBUCHUNG\" value=\"-125000/100\" id=\"S0001\" account=\"A000076\" >\n"
335                      "   <KEYVALUEPAIRS>\n"
336                      "    <PAIR key=\"kmm-match-split\" value=\"S0002\" />\n"
337                      "    <PAIR key=\"kmm-matched-tx\" value=\"&#60;!DOCTYPE MATCH>\n"
338                      "    &#60;CONTAINER>\n"
339                      "     &#60;TRANSACTION postdate=&quot;2010-03-05&quot; memo=&quot;UMBUCHUNG&quot; id=&quot;&quot; commodity=&quot;EUR&quot; entrydate=&quot;2010-03-08&quot; >\n"
340                      "      &#60;SPLITS>\n"
341                      "       &#60;SPLIT payee=&quot;P000010&quot; reconciledate=&quot;&quot; shares=&quot;125000/100&quot; action=&quot;Transfer&quot; bankid=&quot;&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;125000/100&quot; id=&quot;S0001&quot; account=&quot;A000087&quot; />\n"
342                      "       &#60;SPLIT payee=&quot;P000010&quot; reconciledate=&quot;&quot; shares=&quot;-125000/100&quot; action=&quot;&quot; bankid=&quot;A000076-2010-03-05-b6850c0-1&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;-125000/100&quot; id=&quot;S0002&quot; account=&quot;A000076&quot; />\n"
343                      "      &#60;/SPLITS>\n"
344                      "      &#60;KEYVALUEPAIRS>\n"
345                      "       &#60;PAIR key=&quot;Imported&quot; value=&quot;true&quot; />\n"
346                      "      &#60;/KEYVALUEPAIRS>\n"
347                      "     &#60;/TRANSACTION>\n"
348                      "    &#60;/CONTAINER>\n"
349                      "\" />\n"
350                      "    <PAIR key=\"kmm-orig-memo\" value=\"\" />\n"
351                      "   </KEYVALUEPAIRS>\n"
352                      "  </SPLIT>\n"
353                      "  <SPLIT payee=\"P000010\" reconciledate=\"\" shares=\"125000/100\" action=\"Transfer\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"125000/100\" id=\"S0002\" account=\"A000087\" />\n"
354                      " </SPLITS>\n"
355                      "</TRANSACTION>\n"
356                      "</TRANSACTION-CONTAINER>\n"
357                    );
358   QDomDocument doc;
359   QDomElement node;
360   doc.setContent(ref_ok);
361   node = doc.documentElement().firstChild().toElement();
362 
363   try {
364     t = MyMoneyXmlContentHandler::readTransaction(node);
365     QVERIFY(t.pairs().count() == 0);
366     QVERIFY(t.splits().size() == 2);
367     QVERIFY(t.splits()[0].pairs().count() == 3);
368     QVERIFY(t.splits()[1].pairs().count() == 0);
369     QVERIFY(t.splits()[0].isMatched());
370 
371     MyMoneyTransaction ti = t.splits()[0].matchedTransaction();
372     QVERIFY(ti.pairs().count() == 1);
373     QVERIFY(ti.isImported());
374     QVERIFY(ti.splits().count() == 2);
375   } catch (const MyMoneyException &) {
376     QFAIL("Unexpected exception");
377   }
378 }
379 
writeTransaction()380 void MyMoneyXmlContentHandlerTest::writeTransaction()
381 {
382   MyMoneyTransaction t("T000000000000000001");
383   t.setPostDate(QDate(2001, 12, 28));
384   t.setEntryDate(QDate(2003, 9, 29));
385   t.setMemo("Wohnung:Miete");
386   t.setCommodity("EUR");
387   t.setValue("key", "value");
388 
389   MyMoneyTransaction matchedTx;
390   matchedTx.setMemo(QLatin1String("TEST <TEST"));
391   MyMoneySplit matchedSplit;
392   matchedSplit.setMemo(matchedTx.memo());
393   matchedSplit.setAccountId("A000076");
394   matchedTx.addSplit(matchedSplit);
395 
396   MyMoneySplit s;
397   s.setPayeeId("P000001");
398   QList<QString> tagIdList;
399   tagIdList << "G000001";
400   s.setTagIdList(tagIdList);
401   s.setShares(MyMoneyMoney(96379, 100));
402   s.setValue(MyMoneyMoney(96379, 100));
403   s.setAction(MyMoneySplit::actionName(eMyMoney::Split::Action::Withdrawal));
404   s.setAccountId("A000076");
405   s.setReconcileFlag(eMyMoney::Split::State::Reconciled);
406   s.setBankID("SPID");
407   s.addMatch(matchedTx);
408   QVERIFY(s.matchedTransaction() == matchedTx);
409   t.addSplit(s);
410 
411   QDomDocument doc("TEST");
412   QDomElement el = doc.createElement("TRANSACTION-CONTAINER");
413   doc.appendChild(el);
414   MyMoneyXmlContentHandler::writeTransaction(t, doc, el);
415 
416   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
417   QDomElement transactionContainer = doc.documentElement();
418   QVERIFY(transactionContainer.isElement());
419   QCOMPARE(transactionContainer.tagName(), QLatin1String("TRANSACTION-CONTAINER"));
420   QVERIFY(transactionContainer.childNodes().size() == 1);
421   QVERIFY(transactionContainer.childNodes().at(0).isElement());
422 
423   QDomElement transaction = transactionContainer.childNodes().at(0).toElement();
424   QCOMPARE(transaction.tagName(), QLatin1String("TRANSACTION"));
425   QCOMPARE(transaction.attribute("id"), QLatin1String("T000000000000000001"));
426   QCOMPARE(transaction.attribute("postdate"), QLatin1String("2001-12-28"));
427   QCOMPARE(transaction.attribute("commodity"), QLatin1String("EUR"));
428   QCOMPARE(transaction.attribute("memo"), QLatin1String("Wohnung:Miete"));
429   QCOMPARE(transaction.attribute("entrydate"), QLatin1String("2003-09-29"));
430   QCOMPARE(transaction.childNodes().size(), 2);
431 
432   QVERIFY(transaction.childNodes().at(0).isElement());
433   QDomElement splits = transaction.childNodes().at(0).toElement();
434   QCOMPARE(splits.tagName(), QLatin1String("SPLITS"));
435   QCOMPARE(splits.childNodes().size(), 1);
436   QVERIFY(splits.childNodes().at(0).isElement());
437   QDomElement split = splits.childNodes().at(0).toElement();
438   QCOMPARE(split.tagName(), QLatin1String("SPLIT"));
439   QCOMPARE(split.attribute("id"), QLatin1String("S0001"));
440   QCOMPARE(split.attribute("payee"), QLatin1String("P000001"));
441   QCOMPARE(split.attribute("reconcileflag"), QLatin1String("2"));
442   QCOMPARE(split.attribute("shares"), QLatin1String("96379/100"));
443   QCOMPARE(split.attribute("reconciledate"), QString());
444   QCOMPARE(split.attribute("action"), QLatin1String("Withdrawal"));
445   QCOMPARE(split.attribute("bankid"), QLatin1String("SPID"));
446   QCOMPARE(split.attribute("account"), QLatin1String("A000076"));
447   QCOMPARE(split.attribute("number"), QString());
448   QCOMPARE(split.attribute("value"), QLatin1String("96379/100"));
449   QCOMPARE(split.attribute("memo"), QString());
450   QCOMPARE(split.childNodes().size(), 2);
451 
452   QVERIFY(split.childNodes().at(0).isElement());
453   QDomElement tag = split.childNodes().at(0).toElement();
454   QCOMPARE(tag.tagName(), QLatin1String("TAG"));
455   QCOMPARE(tag.attribute("id"), QLatin1String("G000001"));
456   QCOMPARE(tag.childNodes().size(), 0);
457 
458   QDomElement keyValuePairs = transaction.childNodes().at(1).toElement();
459   QCOMPARE(keyValuePairs.tagName(), QLatin1String("KEYVALUEPAIRS"));
460   QCOMPARE(keyValuePairs.childNodes().size(), 1);
461 
462   QVERIFY(keyValuePairs.childNodes().at(0).isElement());
463   QDomElement keyValuePair1 = keyValuePairs.childNodes().at(0).toElement();
464   QCOMPARE(keyValuePair1.tagName(), QLatin1String("PAIR"));
465   QCOMPARE(keyValuePair1.attribute("key"), QLatin1String("key"));
466   QCOMPARE(keyValuePair1.attribute("value"), QLatin1String("value"));
467   QCOMPARE(keyValuePair1.childNodes().size(), 0);
468 
469   auto tread = MyMoneyXmlContentHandler::readTransaction(transaction);
470   QCOMPARE(tread.postDate(), t.postDate());
471   QCOMPARE(tread.memo(), t.memo());
472   QCOMPARE(tread.splits().count(), t.splits().count());
473   // now check the parts that are important in the matched transaction
474   tread = tread.splits().at(0).matchedTransaction();
475   QCOMPARE(tread.postDate(), matchedTx.postDate());
476   QCOMPARE(tread.memo(), matchedTx.memo());
477   QCOMPARE(tread.splits().count(), matchedTx.splits().count());
478   QCOMPARE(tread.splits().count(), 1);
479   QCOMPARE(tread.splits().at(0).memo(), matchedSplit.memo());
480 }
481 
readSplit()482 void MyMoneyXmlContentHandlerTest::readSplit()
483 {
484   MyMoneySplit s;
485   QString ref_ok = QString(
486                      "<!DOCTYPE TEST>\n"
487                      "<SPLIT-CONTAINER>\n"
488                      " <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Deposit\" bankid=\"SPID\" number=\"124\" reconcileflag=\"2\" memo=\"MyMemo\" value=\"96379/1000\" account=\"A000076\" costcenter=\"C000005\">\n"
489                      "  <TAG id=\"G000001\"/>\n"
490                      " </SPLIT>\n"
491                      "</SPLIT-CONTAINER>\n");
492 
493   QString ref_false = QString(
494                         "<!DOCTYPE TEST>\n"
495                         "<SPLIT-CONTAINER>\n"
496                         " <SPLITS payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Deposit\" bankid=\"SPID\" number=\"124\" reconcileflag=\"2\" memo=\"\" value=\"96379/1000\" account=\"A000076\" />\n"
497                         " <TAG id=\"G000001\"/>\n"
498                         "</SPLIT-CONTAINER>\n");
499 
500   QDomDocument doc;
501   QDomElement node;
502   doc.setContent(ref_false);
503   node = doc.documentElement().firstChild().toElement();
504 
505   try {
506     s = MyMoneyXmlContentHandler::readSplit(node);
507     QFAIL("Missing expected exception");
508   } catch (const MyMoneyException &) {
509   }
510 
511   doc.setContent(ref_ok);
512   node = doc.documentElement().firstChild().toElement();
513 
514   try {
515     s = MyMoneyXmlContentHandler::readSplit(node);
516     QCOMPARE(s.id().isEmpty(), true);
517     QCOMPARE(s.payeeId(), QLatin1String("P000001"));
518     QList<QString> tagIdList;
519     tagIdList << QLatin1String("G000001");
520     QCOMPARE(s.tagIdList(), tagIdList);
521     QCOMPARE(s.reconcileDate(), QDate());
522     QCOMPARE(s.shares(), MyMoneyMoney(96379, 100));
523     QCOMPARE(s.value(), MyMoneyMoney(96379, 1000));
524     QCOMPARE(s.number(), QLatin1String("124"));
525     QCOMPARE(s.bankID(), QLatin1String("SPID"));
526     QCOMPARE(s.reconcileFlag(), eMyMoney::Split::State::Reconciled);
527     QCOMPARE(s.action(), MyMoneySplit::actionName(eMyMoney::Split::Action::Deposit));
528     QCOMPARE(s.accountId(), QLatin1String("A000076"));
529     QCOMPARE(s.costCenterId(), QLatin1String("C000005"));
530     QCOMPARE(s.memo(), QLatin1String("MyMemo"));
531   } catch (const MyMoneyException &) {
532   }
533 
534 }
535 
writeSplit()536 void MyMoneyXmlContentHandlerTest::writeSplit()
537 {
538   MyMoneySplit s;
539 
540   s.setPayeeId("P000001");
541   QList<QString> tagIdList;
542   tagIdList << "G000001";
543   s.setTagIdList(tagIdList);
544   s.setShares(MyMoneyMoney(96379, 100));
545   s.setValue(MyMoneyMoney(96379, 1000));
546   s.setAccountId("A000076");
547   s.setCostCenterId("C000005");
548   s.setNumber("124");
549   s.setBankID("SPID");
550   s.setAction(MyMoneySplit::actionName(eMyMoney::Split::Action::Deposit));
551   s.setReconcileFlag(eMyMoney::Split::State::Reconciled);
552 
553   QDomDocument doc("TEST");
554   QDomElement el = doc.createElement("SPLIT-CONTAINER");
555   doc.appendChild(el);
556   MyMoneyXmlContentHandler::writeSplit(s, doc, el);
557 
558   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
559   QDomElement splitContainer = doc.documentElement();
560   QCOMPARE(splitContainer.tagName(), QLatin1String("SPLIT-CONTAINER"));
561   QCOMPARE(splitContainer.childNodes().size(), 1);
562 
563   QCOMPARE(splitContainer.childNodes().at(0).isElement(), true);
564   QDomElement split = splitContainer.childNodes().at(0).toElement();
565   QCOMPARE(split.tagName(), QLatin1String("SPLIT"));
566   QCOMPARE(split.attribute("payee"), QLatin1String("P000001"));
567   QCOMPARE(split.attribute("reconcileflag"), QLatin1String("2"));
568   QCOMPARE(split.attribute("shares"), QLatin1String("96379/100"));
569   QCOMPARE(split.attribute("reconciledate"), QString());
570   QCOMPARE(split.attribute("action"), QLatin1String("Deposit"));
571   QCOMPARE(split.attribute("bankid"), QLatin1String("SPID"));
572   QCOMPARE(split.attribute("account"), QLatin1String("A000076"));
573   QCOMPARE(split.attribute("costcenter"), QLatin1String("C000005"));
574   QCOMPARE(split.attribute("number"), QLatin1String("124"));
575   QCOMPARE(split.attribute("value"), QLatin1String("96379/1000"));
576   QCOMPARE(split.attribute("memo"), QString());
577   QCOMPARE(split.attribute("id"), QString());
578   QCOMPARE(split.childNodes().size(), 1);
579 
580   QCOMPARE(split.childNodes().at(0).isElement(), true);
581   QDomElement tag = split.childNodes().at(0).toElement();
582   QCOMPARE(tag.tagName(), QLatin1String("TAG"));
583   QCOMPARE(tag.attribute("id"), QLatin1String("G000001"));
584   QCOMPARE(tag.childNodes().size(), 0);
585 
586   QString ref = QString(
587                   "<!DOCTYPE TEST>\n"
588                   "<SPLIT-CONTAINER>\n"
589                   " <SPLIT payee=\"P000001\" reconcileflag=\"2\" shares=\"96379/100\" reconciledate=\"\" action=\"Deposit\" bankid=\"SPID\" account=\"A000076\" number=\"124\" value=\"96379/1000\" memo=\"\" id=\"\">\n"
590                   "  <TAG id=\"G000001\"/>\n"
591                   " </SPLIT>\n"
592                   "</SPLIT-CONTAINER>\n");
593 }
594 
testReplaceIDinSplit()595 void MyMoneyXmlContentHandlerTest::testReplaceIDinSplit()
596 {
597   MyMoneySplit s;
598   bool changed;
599 
600   s.setPayeeId("P000001");
601   s.setAccountId("A000076");
602   s.setCostCenterId("C000005");
603 
604   changed = s.replaceId("X0001", "Y00001");
605   QCOMPARE(changed, false);
606   QCOMPARE(s.payeeId(), QLatin1String("P000001"));
607   QCOMPARE(s.accountId(), QLatin1String("A000076"));
608   QCOMPARE(s.costCenterId(), QLatin1String("C000005"));
609 
610   changed = s.replaceId("P000002", "P000001");
611   QCOMPARE(changed, true);
612   QCOMPARE(s.payeeId(), QLatin1String("P000002"));
613   QCOMPARE(s.accountId(), QLatin1String("A000076"));
614   QCOMPARE(s.costCenterId(), QLatin1String("C000005"));
615 
616   changed = s.replaceId("A000079", "A000076");
617   QCOMPARE(changed, true);
618   QCOMPARE(s.payeeId(), QLatin1String("P000002"));
619   QCOMPARE(s.accountId(), QLatin1String("A000079"));
620   QCOMPARE(s.costCenterId(), QLatin1String("C000005"));
621 
622   changed = s.replaceId("C000006", "C000005");
623   QCOMPARE(changed, true);
624   QCOMPARE(s.payeeId(), QLatin1String("P000002"));
625   QCOMPARE(s.accountId(), QLatin1String("A000079"));
626   QCOMPARE(s.costCenterId(), QLatin1String("C000006"));
627 
628   QString ref_ok = QString(
629                      "<!DOCTYPE TEST>\n"
630                      "<SPLIT-CONTAINER>\n"
631                      "  <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-125000/100\" action=\"Transfer\" bankid=\"A000076-2010-03-05-b6850c0-1\" number=\"\" reconcileflag=\"1\" memo=\"UMBUCHUNG\" value=\"-125000/100\" id=\"S0001\" account=\"A000076\" >\n"
632                      "   <KEYVALUEPAIRS>\n"
633                      "    <PAIR key=\"kmm-match-split\" value=\"S0002\" />\n"
634                      "    <PAIR key=\"kmm-matched-tx\" value=\"&#60;!DOCTYPE MATCH>\n"
635                      "    &#60;CONTAINER>\n"
636                      "     &#60;TRANSACTION postdate=&quot;2010-03-05&quot; memo=&quot;UMBUCHUNG&quot; id=&quot;&quot; commodity=&quot;EUR&quot; entrydate=&quot;2010-03-08&quot; >\n"
637                      "      &#60;SPLITS>\n"
638                      "       &#60;SPLIT payee=&quot;P000010&quot; reconciledate=&quot;&quot; shares=&quot;125000/100&quot; action=&quot;Transfer&quot; bankid=&quot;&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;125000/100&quot; id=&quot;S0001&quot; account=&quot;A000087&quot; />\n"
639                      "       &#60;SPLIT payee=&quot;P000011&quot; reconciledate=&quot;&quot; shares=&quot;-125000/100&quot; action=&quot;&quot; bankid=&quot;A000076-2010-03-05-b6850c0-1&quot; number=&quot;&quot; reconcileflag=&quot;0&quot; memo=&quot;UMBUCHUNG&quot; value=&quot;-125000/100&quot; id=&quot;S0002&quot; account=&quot;A000076&quot; />\n"
640                      "      &#60;/SPLITS>\n"
641                      "      &#60;KEYVALUEPAIRS>\n"
642                      "       &#60;PAIR key=&quot;Imported&quot; value=&quot;true&quot; />\n"
643                      "      &#60;/KEYVALUEPAIRS>\n"
644                      "     &#60;/TRANSACTION>\n"
645                      "    &#60;/CONTAINER>\n"
646                      "\" />\n"
647                      "    <PAIR key=\"kmm-orig-memo\" value=\"\" />\n"
648                      "   </KEYVALUEPAIRS>\n"
649                      "  </SPLIT>\n"
650                      "</SPLIT-CONTAINER>\n"
651                    );
652   QDomDocument doc;
653   QDomElement node;
654   doc.setContent(ref_ok);
655   node = doc.documentElement().firstChild().toElement();
656 
657   try {
658     s = MyMoneyXmlContentHandler::readSplit(node);
659     QCOMPARE(s.payeeId(), QLatin1String("P000001"));
660     QCOMPARE(s.replaceId("P2", "P1"), false);
661     QCOMPARE(s.matchedTransaction().splits()[0].payeeId(), QLatin1String("P000010"));
662     QCOMPARE(s.matchedTransaction().splits()[1].payeeId(), QLatin1String("P000011"));
663     QCOMPARE(s.replaceId("P0010", "P000010"), true);
664     QCOMPARE(s.matchedTransaction().splits()[0].payeeId(), QLatin1String("P0010"));
665     QCOMPARE(s.matchedTransaction().splits()[1].payeeId(), QLatin1String("P000011"));
666     QCOMPARE(s.replaceId("P0011", "P000011"), true);
667     QCOMPARE(s.matchedTransaction().splits()[0].payeeId(), QLatin1String("P0010"));
668     QCOMPARE(s.matchedTransaction().splits()[1].payeeId(), QLatin1String("P0011"));
669 
670   } catch (const MyMoneyException &) {
671     QFAIL("Unexpected exception");
672   }
673 }
674 
readAccount()675 void MyMoneyXmlContentHandlerTest::readAccount()
676 {
677   MyMoneyAccount a;
678   QString ref_ok = QString(
679                      "<!DOCTYPE TEST>\n"
680                      "<ACCOUNT-CONTAINER>\n"
681                      " <ACCOUNT parentaccount=\"Parent\" lastmodified=\"%1\" lastreconciled=\"\" institution=\"B000001\" number=\"465500\" opened=\"%2\" type=\"9\" id=\"A000001\" name=\"AccountName\" description=\"Desc\" >\n"
682                      "  <SUBACCOUNTS>\n"
683                      "   <SUBACCOUNT id=\"A000002\" />\n"
684                      "   <SUBACCOUNT id=\"A000003\" />\n"
685                      "  </SUBACCOUNTS>\n"
686                      "  <KEYVALUEPAIRS>\n"
687                      "   <PAIR key=\"key\" value=\"value\" />\n"
688                      "   <PAIR key=\"Key\" value=\"Value\" />\n"
689                      "   <PAIR key=\"reconciliationHistory\" value=\"2011-01-01:123/100;2011-02-01:114/25\"/>\n"
690                      "   <PAIR key=\"lastStatementDate\" value=\"2011-01-01\"/>\n"
691                      "  </KEYVALUEPAIRS>\n"
692                      " </ACCOUNT>\n"
693                      "</ACCOUNT-CONTAINER>\n").
694                    arg(QDate::currentDate().toString(Qt::ISODate)).arg(QDate::currentDate().toString(Qt::ISODate));
695 
696   QString ref_false = QString(
697                         "<!DOCTYPE TEST>\n"
698                         "<ACCOUNT-CONTAINER>\n"
699                         " <KACCOUNT parentaccount=\"Parent\" lastmodified=\"%1\" lastreconciled=\"\" institution=\"B000001\" number=\"465500\" opened=\"%2\" type=\"9\" id=\"A000001\" name=\"AccountName\" description=\"Desc\" >\n"
700                         "  <SUBACCOUNTS>\n"
701                         "   <SUBACCOUNT id=\"A000002\" />\n"
702                         "   <SUBACCOUNT id=\"A000003\" />\n"
703                         "  </SUBACCOUNTS>\n"
704                         "  <KEYVALUEPAIRS>\n"
705                         "   <PAIR key=\"key\" value=\"value\" />\n"
706                         "   <PAIR key=\"Key\" value=\"Value\" />\n"
707                         "  </KEYVALUEPAIRS>\n"
708                         " </KACCOUNT>\n"
709                         "</ACCOUNT-CONTAINER>\n").
710                       arg(QDate::currentDate().toString(Qt::ISODate)).arg(QDate::currentDate().toString(Qt::ISODate));
711 
712   QDomDocument doc;
713   QDomElement node;
714   doc.setContent(ref_false);
715   node = doc.documentElement().firstChild().toElement();
716 
717   try {
718     a = MyMoneyXmlContentHandler::readAccount(node);
719     QFAIL("Missing expected exception");
720   } catch (const MyMoneyException &) {
721   }
722 
723   doc.setContent(ref_ok);
724   node = doc.documentElement().firstChild().toElement();
725 
726   a.addAccountId("TEST");
727   a.setValue("KEY", "VALUE");
728 
729   try {
730     a = MyMoneyXmlContentHandler::readAccount(node);
731     QCOMPARE(a.id(), QStringLiteral("A000001"));
732     QCOMPARE(a.name(), QStringLiteral("AccountName"));
733     QCOMPARE(a.parentAccountId(), QStringLiteral("Parent"));
734     QCOMPARE(a.lastModified(), QDate::currentDate());
735     QCOMPARE(a.lastReconciliationDate(), QDate());
736     QCOMPARE(a.institutionId(), QStringLiteral("B000001"));
737     QCOMPARE(a.number(), QStringLiteral("465500"));
738     QCOMPARE(a.openingDate(), QDate::currentDate());
739     QCOMPARE(a.accountType(), eMyMoney::Account::Type::Asset);
740     QCOMPARE(a.description(), QStringLiteral("Desc"));
741     QCOMPARE(a.accountList().count(), 2);
742     QCOMPARE(a.accountList()[0], QStringLiteral("A000002"));
743     QCOMPARE(a.accountList()[1], QStringLiteral("A000003"));
744     QCOMPARE(a.pairs().count(), 3);
745     QCOMPARE(a.value("key"), QStringLiteral("value"));
746     QCOMPARE(a.value("Key"), QStringLiteral("Value"));
747     QCOMPARE(a.pairs().contains("lastStatementDate"), false);
748     QCOMPARE(a.reconciliationHistory().count(), 2);
749     QCOMPARE(a.reconciliationHistory()[QDate(2011, 1, 1)].toString(), MyMoneyMoney(123, 100).toString());
750     QCOMPARE(a.reconciliationHistory()[QDate(2011, 2, 1)].toString(), MyMoneyMoney(456, 100).toString());
751   } catch (const MyMoneyException &) {
752     QFAIL("Unexpected exception");
753   }
754 }
755 
writeAccount()756 void MyMoneyXmlContentHandlerTest::writeAccount()
757 {
758   QString id = "A000001";
759   QString institutionid = "B000001";
760   QString parent = "Parent";
761 
762   MyMoneyAccount r;
763   r.setAccountType(eMyMoney::Account::Type::Asset);
764   r.setOpeningDate(QDate::currentDate());
765   r.setLastModified(QDate::currentDate());
766   r.setDescription("Desc");
767   r.setName("AccountName");
768   r.setNumber("465500");
769   r.setParentAccountId(parent);
770   r.setInstitutionId(institutionid);
771   r.setValue(QString("key"), "value");
772   r.addAccountId("A000002");
773   r.addReconciliation(QDate(2011, 1, 1), MyMoneyMoney(123, 100));
774   r.addReconciliation(QDate(2011, 2, 1), MyMoneyMoney(456, 100));
775 
776   QCOMPARE(r.pairs().count(), 2);
777   QCOMPARE(r.value("key"), QLatin1String("value"));
778   QCOMPARE(r.value("reconciliationHistory"), QLatin1String("2011-01-01:123/100;2011-02-01:114/25"));
779 
780   MyMoneyAccount a(id, r);
781 
782   QDomDocument doc("TEST");
783   QDomElement el = doc.createElement("ACCOUNT-CONTAINER");
784   doc.appendChild(el);
785   MyMoneyXmlContentHandler::writeAccount(a, doc, el);
786 
787   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
788   QDomElement accountContainer = doc.documentElement();
789   QVERIFY(accountContainer.isElement());
790   QCOMPARE(accountContainer.tagName(), QLatin1String("ACCOUNT-CONTAINER"));
791   QVERIFY(accountContainer.childNodes().size() == 1);
792   QVERIFY(accountContainer.childNodes().at(0).isElement());
793 
794   QDomElement account = accountContainer.childNodes().at(0).toElement();
795   QCOMPARE(account.tagName(), QLatin1String("ACCOUNT"));
796   QCOMPARE(account.attribute("id"), QLatin1String("A000001"));
797   QCOMPARE(account.attribute("lastreconciled"), QString());
798   QCOMPARE(account.attribute("institution"), QLatin1String("B000001"));
799   QCOMPARE(account.attribute("name"), QLatin1String("AccountName"));
800   QCOMPARE(account.attribute("number"), QLatin1String("465500"));
801   QCOMPARE(account.attribute("description"), QLatin1String("Desc"));
802   QCOMPARE(account.attribute("parentaccount"), QLatin1String("Parent"));
803   QCOMPARE(account.attribute("opened"), QDate::currentDate().toString(Qt::ISODate));
804   QCOMPARE(account.attribute("type"), QLatin1String("9"));
805   QCOMPARE(account.attribute("lastmodified"), QDate::currentDate().toString(Qt::ISODate));
806   QCOMPARE(account.attribute("id"), QLatin1String("A000001"));
807   QCOMPARE(account.childNodes().size(), 2);
808 
809   QVERIFY(account.childNodes().at(0).isElement());
810   QDomElement subAccounts = account.childNodes().at(0).toElement();
811   QCOMPARE(subAccounts.tagName(), QLatin1String("SUBACCOUNTS"));
812   QCOMPARE(subAccounts.childNodes().size(), 1);
813   QVERIFY(subAccounts.childNodes().at(0).isElement());
814   QDomElement subAccount = subAccounts.childNodes().at(0).toElement();
815   QCOMPARE(subAccount.tagName(), QLatin1String("SUBACCOUNT"));
816   QCOMPARE(subAccount.attribute("id"), QLatin1String("A000002"));
817   QCOMPARE(subAccount.childNodes().size(), 0);
818 
819   QDomElement keyValuePairs = account.childNodes().at(1).toElement();
820   QCOMPARE(keyValuePairs.tagName(), QLatin1String("KEYVALUEPAIRS"));
821   QCOMPARE(keyValuePairs.childNodes().size(), 2);
822 
823   QVERIFY(keyValuePairs.childNodes().at(0).isElement());
824   QDomElement keyValuePair1 = keyValuePairs.childNodes().at(0).toElement();
825   QCOMPARE(keyValuePair1.tagName(), QLatin1String("PAIR"));
826   QCOMPARE(keyValuePair1.attribute("key"), QLatin1String("key"));
827   QCOMPARE(keyValuePair1.attribute("value"), QLatin1String("value"));
828   QCOMPARE(keyValuePair1.childNodes().size(), 0);
829 
830   QVERIFY(keyValuePairs.childNodes().at(1).isElement());
831   QDomElement keyValuePair2 = keyValuePairs.childNodes().at(1).toElement();
832   QCOMPARE(keyValuePair2.tagName(), QLatin1String("PAIR"));
833   QCOMPARE(keyValuePair2.attribute("key"), QLatin1String("reconciliationHistory"));
834   QCOMPARE(keyValuePair2.attribute("value"), QLatin1String("2011-01-01:123/100;2011-02-01:114/25"));
835   QCOMPARE(keyValuePair2.childNodes().size(), 0);
836 }
837 
readWritePayee()838 void MyMoneyXmlContentHandlerTest::readWritePayee()
839 {
840   QDomDocument doc;
841   QDomElement parent = doc.createElement("Test");
842   doc.appendChild(parent);
843   MyMoneyPayee payee1("some random id"); //if the ID isn't set, w ethrow an exception
844   MyMoneyXmlContentHandler::writePayee(payee1, doc, parent);
845   QString temp1 = "Account1";
846   payee1.setDefaultAccountId(temp1);
847   MyMoneyXmlContentHandler::writePayee(payee1, doc, parent);
848   QString temp2 = "Account2";
849   payee1.setDefaultAccountId(temp2);
850   MyMoneyXmlContentHandler::writePayee(payee1, doc, parent);
851   payee1.setDefaultAccountId();
852   MyMoneyXmlContentHandler::writePayee(payee1, doc, parent);
853   QDomElement el = parent.firstChild().toElement();
854   QVERIFY(!el.isNull());
855   auto payee2 = MyMoneyXmlContentHandler::readPayee(el);
856   QVERIFY(payee2.defaultAccountId().isEmpty());
857   el = el.nextSibling().toElement();
858   QVERIFY(!el.isNull());
859   auto payee3 = MyMoneyXmlContentHandler::readPayee(el);
860   QVERIFY(!payee3.defaultAccountId().isEmpty());
861   QVERIFY(payee3.defaultAccountId() == temp1);
862   el = el.nextSibling().toElement();
863   QVERIFY(!el.isNull());
864   auto payee4 = MyMoneyXmlContentHandler::readPayee(el);
865   QVERIFY(!payee4.defaultAccountId().isEmpty());
866   QVERIFY(payee4.defaultAccountId() == temp2);
867   el = el.nextSibling().toElement();
868   QVERIFY(!el.isNull());
869   auto payee5 = MyMoneyXmlContentHandler::readPayee(el);
870   QVERIFY(payee5.defaultAccountId().isEmpty());
871 }
872 
readWriteTag()873 void MyMoneyXmlContentHandlerTest::readWriteTag()
874 {
875   QDomDocument doc;
876   QDomElement parent = doc.createElement("Test");
877   doc.appendChild(parent);
878   MyMoneyTag tag1("some random id"); //if the ID isn't set, w ethrow an exception
879   tag1.setName(QStringLiteral("MyTagName"));
880   tag1.setNamedTagColor(QStringLiteral("red"));
881   tag1.setNotes(QStringLiteral("Notes for a tag"));
882 
883   MyMoneyXmlContentHandler::writeTag(tag1, doc, parent);
884   QDomElement el = parent.firstChild().toElement();
885   QVERIFY(!el.isNull());
886   auto tag2 = MyMoneyXmlContentHandler::readTag(el);
887   QCOMPARE(tag1.name(), tag2.name());
888   QCOMPARE(tag1.notes(), tag2.notes());
889   QCOMPARE(tag1.tagColor(), tag2.tagColor());
890 }
891 
readInstitution()892 void MyMoneyXmlContentHandlerTest::readInstitution()
893 {
894   MyMoneyInstitution i;
895   QString ref_ok = QString(
896                      "<!DOCTYPE TEST>\n"
897                      "<INSTITUTION-CONTAINER>\n"
898                      " <INSTITUTION sortcode=\"sortcode\" id=\"I00001\" manager=\"manager\" name=\"name\" >\n"
899                      "  <ADDRESS street=\"street\" zip=\"postcode\" city=\"town\" telephone=\"telephone\" />\n"
900                      "  <ACCOUNTIDS>\n"
901                      "   <ACCOUNTID id=\"A000001\" />\n"
902                      "   <ACCOUNTID id=\"A000003\" />\n"
903                      "  </ACCOUNTIDS>\n"
904                      "  <KEYVALUEPAIRS>\n"
905                      "   <PAIR key=\"key\" value=\"value\" />\n"
906                      "  </KEYVALUEPAIRS>\n"
907                      " </INSTITUTION>\n"
908                      "</INSTITUTION-CONTAINER>\n");
909 
910   QString ref_false = QString(
911                         "<!DOCTYPE TEST>\n"
912                         "<INSTITUTION-CONTAINER>\n"
913                         " <KINSTITUTION sortcode=\"sortcode\" id=\"I00001\" manager=\"manager\" name=\"name\" >\n"
914                         "  <ADDRESS street=\"street\" zip=\"postcode\" city=\"town\" telephone=\"telephone\" />\n"
915                         "  <ACCOUNTIDS>\n"
916                         "   <ACCOUNTID id=\"A000001\" />\n"
917                         "   <ACCOUNTID id=\"A000003\" />\n"
918                         "  </ACCOUNTIDS>\n"
919                         " </KINSTITUTION>\n"
920                         "</INSTITUTION-CONTAINER>\n");
921 
922   QDomDocument doc;
923   QDomElement node;
924 
925   doc.setContent(ref_false);
926   node = doc.documentElement().firstChild().toElement();
927   try {
928     i = MyMoneyXmlContentHandler::readInstitution(node);
929     QFAIL("Missing expected exception");
930   } catch (const MyMoneyException &) {
931   }
932 
933   i.addAccountId("TEST");
934 
935   doc.setContent(ref_ok);
936   node = doc.documentElement().firstChild().toElement();
937   try {
938     QStringList alist;
939     alist << "A000001" << "A000003";
940     i = MyMoneyXmlContentHandler::readInstitution(node);
941 
942     QVERIFY(i.sortcode() == "sortcode");
943     QVERIFY(i.id() == "I00001");
944     QVERIFY(i.manager() == "manager");
945     QVERIFY(i.name() == "name");
946     QVERIFY(i.street() == "street");
947     QVERIFY(i.postcode() == "postcode");
948     QVERIFY(i.city() == "town");
949     QVERIFY(i.telephone() == "telephone");
950     QVERIFY(i.accountList() == alist);
951     QVERIFY(i.value(QString("key")) == "value");
952 
953   } catch (const MyMoneyException &) {
954     QFAIL("Unexpected exception");
955   }
956 }
957 
writeInstitution()958 void MyMoneyXmlContentHandlerTest::writeInstitution()
959 {
960   MyMoneyInstitution n("name", "town", "street", "postcode",
961                        "telephone", "manager", "sortcode");;
962 
963   n.addAccountId("A000001");
964   n.addAccountId("A000003");
965   n.setValue(QString("key"), "value");
966 
967   QDomDocument doc("TEST");
968   QDomElement el = doc.createElement("INSTITUTION-CONTAINER");
969   doc.appendChild(el);
970 
971   MyMoneyInstitution i("I00001", n);
972   MyMoneyXmlContentHandler::writeInstitution(i, doc, el);
973 
974   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
975   QDomElement institutionContainer = doc.documentElement();
976   QVERIFY(institutionContainer.isElement());
977   QCOMPARE(institutionContainer.tagName(), QLatin1String("INSTITUTION-CONTAINER"));
978   QVERIFY(institutionContainer.childNodes().size() == 1);
979   QVERIFY(institutionContainer.elementsByTagName("INSTITUTION").at(0).isElement());
980 
981   QDomElement institution = institutionContainer.elementsByTagName("INSTITUTION").at(0).toElement();
982   QCOMPARE(institution.tagName(), QLatin1String("INSTITUTION"));
983   QCOMPARE(institution.attribute("id"), QLatin1String("I00001"));
984   QCOMPARE(institution.attribute("manager"), QLatin1String("manager"));
985   QCOMPARE(institution.attribute("name"), QLatin1String("name"));
986   QCOMPARE(institution.attribute("sortcode"), QLatin1String("sortcode"));
987   QCOMPARE(institution.childNodes().size(), 3);
988 
989   QVERIFY(institution.childNodes().at(0).isElement());
990   QDomElement address = institution.childNodes().at(0).toElement();
991   QCOMPARE(address.tagName(), QLatin1String("ADDRESS"));
992   QCOMPARE(address.attribute("street"), QLatin1String("street"));
993   QCOMPARE(address.attribute("telephone"), QLatin1String("telephone"));
994   QCOMPARE(address.attribute("zip"), QLatin1String("postcode"));
995   QCOMPARE(address.attribute("city"), QLatin1String("town"));
996   QCOMPARE(address.childNodes().size(), 0);
997 
998   QVERIFY(institution.childNodes().at(1).isElement());
999   QDomElement accountIds = institution.childNodes().at(1).toElement();
1000   QCOMPARE(accountIds.tagName(), QLatin1String("ACCOUNTIDS"));
1001   QCOMPARE(accountIds.childNodes().size(), 2);
1002 
1003   QVERIFY(accountIds.childNodes().at(0).isElement());
1004   QDomElement account1 = accountIds.childNodes().at(0).toElement();
1005   QCOMPARE(account1.tagName(), QLatin1String("ACCOUNTID"));
1006   QCOMPARE(account1.attribute("id"), QLatin1String("A000001"));
1007   QCOMPARE(account1.childNodes().size(), 0);
1008 
1009   QVERIFY(accountIds.childNodes().at(1).isElement());
1010   QDomElement account2 = accountIds.childNodes().at(1).toElement();
1011   QCOMPARE(account2.tagName(), QLatin1String("ACCOUNTID"));
1012   QCOMPARE(account2.attribute("id"), QLatin1String("A000003"));
1013   QCOMPARE(account2.childNodes().size(), 0);
1014 
1015   QVERIFY(institution.childNodes().at(2).isElement());
1016   QDomElement keyValuePairs = institution.childNodes().at(2).toElement();
1017   QCOMPARE(keyValuePairs.tagName(), QLatin1String("KEYVALUEPAIRS"));
1018   QCOMPARE(keyValuePairs.childNodes().size(), 1);
1019 
1020   QVERIFY(keyValuePairs.childNodes().at(0).isElement());
1021   QDomElement keyValuePair1 = keyValuePairs.childNodes().at(0).toElement();
1022   QCOMPARE(keyValuePair1.tagName(), QLatin1String("PAIR"));
1023   QCOMPARE(keyValuePair1.attribute("key"), QLatin1String("key"));
1024   QCOMPARE(keyValuePair1.attribute("value"), QLatin1String("value"));
1025   QCOMPARE(keyValuePair1.childNodes().size(), 0);
1026 }
1027 
readSchedule()1028 void MyMoneyXmlContentHandlerTest::readSchedule()
1029 {
1030   MyMoneySchedule sch;
1031 
1032   QString ref_ok1 = QString(
1033                       "<!DOCTYPE TEST>\n"
1034                       "<SCHEDULE-CONTAINER>\n"
1035                       " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n" // krazy:exclude=spelling
1036                       "  <PAYMENTS>\n"
1037                       "   <PAYMENT date=\"%3\" />\n"
1038                       "  </PAYMENTS>\n"
1039                       "  <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
1040                       "   <SPLITS>\n"
1041                       "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
1042                       "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
1043                       "   </SPLITS>\n"
1044                       "   <KEYVALUEPAIRS>\n"
1045                       "    <PAIR key=\"key\" value=\"value\" />\n"
1046                       "   </KEYVALUEPAIRS>\n"
1047                       "  </TRANSACTION>\n"
1048                       " </SCHEDULED_TX>\n"
1049                       "</SCHEDULE-CONTAINER>\n"
1050                     ).arg(QDate::currentDate().toString(Qt::ISODate))
1051                     .arg(QDate::currentDate().toString(Qt::ISODate))
1052                     .arg(QDate::currentDate().toString(Qt::ISODate));
1053 
1054   // diff to ref_ok1 is that we now have an empty entrydate
1055   // in the transaction parameters
1056   QString ref_ok2 = QString(
1057                       "<!DOCTYPE TEST>\n"
1058                       "<SCHEDULE-CONTAINER>\n"
1059                       " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n" // krazy:exclude=spelling
1060                       "  <PAYMENTS>\n"
1061                       "   <PAYMENT date=\"%3\" />\n"
1062                       "  </PAYMENTS>\n"
1063                       "  <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
1064                       "   <SPLITS>\n"
1065                       "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
1066                       "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
1067                       "   </SPLITS>\n"
1068                       "   <KEYVALUEPAIRS>\n"
1069                       "    <PAIR key=\"key\" value=\"value\" />\n"
1070                       "   </KEYVALUEPAIRS>\n"
1071                       "  </TRANSACTION>\n"
1072                       " </SCHEDULED_TX>\n"
1073                       "</SCHEDULE-CONTAINER>\n"
1074                     ).arg(QDate::currentDate().toString(Qt::ISODate))
1075                     .arg(QDate::currentDate().toString(Qt::ISODate))
1076                     .arg(QDate::currentDate().toString(Qt::ISODate));
1077 
1078   QString ref_false = QString(
1079                         "<!DOCTYPE TEST>\n"
1080                         "<SCHEDULE-CONTAINER>\n"
1081                         " <SCHEDULE startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n" // krazy:exclude=spelling
1082                         "  <PAYMENTS count=\"1\" >\n"
1083                         "   <PAYMENT date=\"%3\" />\n"
1084                         "  </PAYMENTS>\n"
1085                         "  <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
1086                         "   <SPLITS>\n"
1087                         "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" bankid=\"SPID1\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
1088                         "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" bankid=\"SPID2\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
1089                         "   </SPLITS>\n"
1090                         "   <KEYVALUEPAIRS>\n"
1091                         "    <PAIR key=\"key\" value=\"value\" />\n"
1092                         "   </KEYVALUEPAIRS>\n"
1093                         "  </TRANSACTION>\n"
1094                         " </SCHEDULED_TX>\n"
1095                         "</SCHEDULE-CONTAINER>\n"
1096                       ).arg(QDate::currentDate().toString(Qt::ISODate))
1097                       .arg(QDate::currentDate().toString(Qt::ISODate))
1098                       .arg(QDate::currentDate().toString(Qt::ISODate));
1099 
1100   QDomDocument doc;
1101   QDomElement node;
1102   doc.setContent(ref_false);
1103   node = doc.documentElement().firstChild().toElement();
1104 
1105   try {
1106     sch = MyMoneyXmlContentHandler::readSchedule(node);
1107     QFAIL("Missing expected exception");
1108   } catch (const MyMoneyException &) {
1109   }
1110 
1111   doc.setContent(ref_ok1);
1112   node = doc.documentElement().firstChild().toElement();
1113 
1114 
1115   try {
1116     sch = MyMoneyXmlContentHandler::readSchedule(node);
1117     QCOMPARE(sch.id(), QLatin1String("SCH0002"));
1118     QCOMPARE(sch.nextDueDate(), QDate::currentDate().addDays(7));
1119     QCOMPARE(sch.startDate(), QDate::currentDate());
1120     QCOMPARE(sch.endDate(), QDate());
1121     QCOMPARE(sch.autoEnter(), true);
1122     QCOMPARE(sch.isFixed(), true);
1123     QCOMPARE(sch.weekendOption(), Schedule::WeekendOption::MoveNothing);
1124     QCOMPARE(sch.lastPayment(), QDate::currentDate());
1125     QCOMPARE(sch.paymentType(), Schedule::PaymentType::DirectDebit);
1126     QCOMPARE(sch.type(), Schedule::Type::Bill);
1127     QCOMPARE(sch.name(), QLatin1String("A Name"));
1128     QCOMPARE(sch.baseOccurrence(), Schedule::Occurrence::Weekly);
1129     QCOMPARE(sch.occurrenceMultiplier(), 1);
1130     QCOMPARE(sch.nextDueDate(), sch.lastPayment().addDays(7));
1131     QCOMPARE(sch.recordedPayments().count(), 1);
1132     QCOMPARE(sch.recordedPayments()[0], QDate::currentDate());
1133   } catch (const MyMoneyException &) {
1134     QFAIL("Unexpected exception");
1135   }
1136 
1137   doc.setContent(ref_ok2);
1138   node = doc.documentElement().firstChild().toElement();
1139 
1140 
1141   try {
1142     sch = MyMoneyXmlContentHandler::readSchedule(node);
1143     QCOMPARE(sch.id(), QLatin1String("SCH0002"));
1144     QCOMPARE(sch.nextDueDate(), QDate::currentDate().addDays(7));
1145     QCOMPARE(sch.startDate(), QDate::currentDate());
1146     QCOMPARE(sch.endDate(), QDate());
1147     QCOMPARE(sch.autoEnter(), true);
1148     QCOMPARE(sch.isFixed(), true);
1149     QCOMPARE(sch.weekendOption(), Schedule::WeekendOption::MoveNothing);
1150     QCOMPARE(sch.lastPayment(), QDate::currentDate());
1151     QCOMPARE(sch.paymentType(), Schedule::PaymentType::DirectDebit);
1152     QCOMPARE(sch.type(), Schedule::Type::Bill);
1153     QCOMPARE(sch.name(), QLatin1String("A Name"));
1154     QCOMPARE(sch.baseOccurrence(), Schedule::Occurrence::Weekly);
1155     QCOMPARE(sch.occurrenceMultiplier(), 1);
1156     QCOMPARE(sch.nextDueDate(), sch.lastPayment().addDays(7));
1157     QCOMPARE(sch.recordedPayments().count(), 1);
1158     QCOMPARE(sch.recordedPayments()[0], QDate::currentDate());
1159   } catch (const MyMoneyException &) {
1160     QFAIL("Unexpected exception");
1161   }
1162 }
1163 
writeSchedule()1164 void MyMoneyXmlContentHandlerTest::writeSchedule()
1165 {
1166   MyMoneySchedule tempSch("A Name",
1167                       Schedule::Type::Bill,
1168                       Schedule::Occurrence::Weekly, 123,
1169                       Schedule::PaymentType::DirectDebit,
1170                       QDate::currentDate(),
1171                       QDate(),
1172                       true,
1173                       true);
1174 
1175   MyMoneySchedule sch("SCH0001", tempSch);
1176   sch.setLastPayment(QDate::currentDate());
1177   sch.recordPayment(QDate::currentDate());
1178 
1179   MyMoneyTransaction t("T000000000000000001");
1180   t.setPostDate(QDate(2001, 12, 28));
1181   t.setEntryDate(QDate(2003, 9, 29));
1182   t.setMemo("Wohnung:Miete");
1183   t.setCommodity("EUR");
1184   t.setValue("key", "value");
1185 
1186   MyMoneySplit s;
1187   s.setPayeeId("P000001");
1188   s.setShares(MyMoneyMoney(96379, 100));
1189   s.setValue(MyMoneyMoney(96379, 100));
1190   s.setAccountId("A000076");
1191   s.setBankID("SPID1");
1192   s.setReconcileFlag(eMyMoney::Split::State::Reconciled);
1193   t.addSplit(s);
1194 
1195   s.setPayeeId("P000001");
1196   s.setShares(MyMoneyMoney(-96379, 100));
1197   s.setValue(MyMoneyMoney(-96379, 100));
1198   s.setAccountId("A000276");
1199   s.setBankID("SPID2");
1200   s.setReconcileFlag(eMyMoney::Split::State::Cleared);
1201   s.clearId();
1202   t.addSplit(s);
1203 
1204   sch.setTransaction(t);
1205 
1206   QDomDocument doc("TEST");
1207   QDomElement el = doc.createElement("SCHEDULE-CONTAINER");
1208   doc.appendChild(el);
1209   MyMoneyXmlContentHandler::writeSchedule(sch, doc, el);
1210 
1211   QCOMPARE(doc.doctype().name(), QLatin1String("TEST"));
1212   QDomElement scheduleContainer = doc.documentElement();
1213   QVERIFY(scheduleContainer.isElement());
1214   QCOMPARE(scheduleContainer.tagName(), QLatin1String("SCHEDULE-CONTAINER"));
1215   QCOMPARE(scheduleContainer.childNodes().size(), 1);
1216   QVERIFY(scheduleContainer.childNodes().at(0).isElement());
1217 
1218   QDomElement schedule = scheduleContainer.childNodes().at(0).toElement();
1219   QCOMPARE(schedule.tagName(), QLatin1String("SCHEDULED_TX"));
1220   QCOMPARE(schedule.attribute("id"), QLatin1String("SCH0001"));
1221   QCOMPARE(schedule.attribute("paymentType"), QLatin1String("1"));
1222   QCOMPARE(schedule.attribute("autoEnter"), QLatin1String("1"));
1223   QCOMPARE(schedule.attribute("occurenceMultiplier"), QLatin1String("123")); // krazy:exclude=spelling
1224   QCOMPARE(schedule.attribute("startDate"), QDate::currentDate().toString(Qt::ISODate));
1225   QCOMPARE(schedule.attribute("lastPayment"), QDate::currentDate().toString(Qt::ISODate));
1226   QCOMPARE(schedule.attribute("occurenceMultiplier"), QLatin1String("123")); // krazy:exclude=spelling
1227   QCOMPARE(schedule.attribute("occurence"), QLatin1String("4")); // krazy:exclude=spelling
1228   QCOMPARE(schedule.attribute("type"), QLatin1String("1"));
1229   QCOMPARE(schedule.attribute("name"), QLatin1String("A Name"));
1230   QCOMPARE(schedule.attribute("fixed"), QLatin1String("1"));
1231   QCOMPARE(schedule.attribute("endDate"), QString());
1232   QCOMPARE(schedule.childNodes().size(), 2);
1233 
1234   QVERIFY(schedule.childNodes().at(0).isElement());
1235   QDomElement payments = schedule.childNodes().at(0).toElement();
1236 
1237   QVERIFY(schedule.childNodes().at(1).isElement());
1238   QDomElement transaction = schedule.childNodes().at(1).toElement();
1239   QCOMPARE(transaction.tagName(), QLatin1String("TRANSACTION"));
1240   QCOMPARE(transaction.attribute("id"), QString());
1241   QCOMPARE(transaction.attribute("postdate"), QLatin1String("2001-12-28"));
1242   QCOMPARE(transaction.attribute("commodity"), QLatin1String("EUR"));
1243   QCOMPARE(transaction.attribute("memo"), QLatin1String("Wohnung:Miete"));
1244   QCOMPARE(transaction.attribute("entrydate"), QLatin1String("2003-09-29"));
1245   QCOMPARE(transaction.childNodes().size(), 2);
1246 
1247   QVERIFY(transaction.childNodes().at(0).isElement());
1248   QDomElement splits = transaction.childNodes().at(0).toElement();
1249   QCOMPARE(splits.tagName(), QLatin1String("SPLITS"));
1250   QCOMPARE(splits.childNodes().size(), 2);
1251   QVERIFY(splits.childNodes().at(0).isElement());
1252   QDomElement split1 = splits.childNodes().at(0).toElement();
1253   QCOMPARE(split1.tagName(), QLatin1String("SPLIT"));
1254   QCOMPARE(split1.attribute("id"), QLatin1String("S0001"));
1255   QCOMPARE(split1.attribute("payee"), QLatin1String("P000001"));
1256   QCOMPARE(split1.attribute("reconcileflag"), QLatin1String("2"));
1257   QCOMPARE(split1.attribute("shares"), QLatin1String("96379/100"));
1258   QCOMPARE(split1.attribute("reconciledate"), QString());
1259   QCOMPARE(split1.attribute("action"), QString());
1260   QCOMPARE(split1.attribute("bankid"), QString());
1261   QCOMPARE(split1.attribute("account"), QLatin1String("A000076"));
1262   QCOMPARE(split1.attribute("number"), QString());
1263   QCOMPARE(split1.attribute("value"), QLatin1String("96379/100"));
1264   QCOMPARE(split1.attribute("memo"), QString());
1265   QCOMPARE(split1.childNodes().size(), 0);
1266 
1267   QVERIFY(splits.childNodes().at(1).isElement());
1268   QDomElement split2 = splits.childNodes().at(1).toElement();
1269   QCOMPARE(split2.tagName(), QLatin1String("SPLIT"));
1270   QCOMPARE(split2.attribute("id"), QLatin1String("S0002"));
1271   QCOMPARE(split2.attribute("payee"), QLatin1String("P000001"));
1272   QCOMPARE(split2.attribute("reconcileflag"), QLatin1String("1"));
1273   QCOMPARE(split2.attribute("shares"), QLatin1String("-96379/100"));
1274   QCOMPARE(split2.attribute("reconciledate"), QString());
1275   QCOMPARE(split2.attribute("action"), QString());
1276   QCOMPARE(split2.attribute("bankid"), QString());
1277   QCOMPARE(split2.attribute("account"), QLatin1String("A000276"));
1278   QCOMPARE(split2.attribute("number"), QString());
1279   QCOMPARE(split2.attribute("value"), QLatin1String("-96379/100"));
1280   QCOMPARE(split2.attribute("memo"), QString());
1281   QCOMPARE(split2.childNodes().size(), 0);
1282 
1283   QDomElement keyValuePairs = transaction.childNodes().at(1).toElement();
1284   QCOMPARE(keyValuePairs.tagName(), QLatin1String("KEYVALUEPAIRS"));
1285   QCOMPARE(keyValuePairs.childNodes().size(), 1);
1286 
1287   QVERIFY(keyValuePairs.childNodes().at(0).isElement());
1288   QDomElement keyValuePair1 = keyValuePairs.childNodes().at(0).toElement();
1289   QCOMPARE(keyValuePair1.tagName(), QLatin1String("PAIR"));
1290   QCOMPARE(keyValuePair1.attribute("key"), QLatin1String("key"));
1291   QCOMPARE(keyValuePair1.attribute("value"), QLatin1String("value"));
1292   QCOMPARE(keyValuePair1.childNodes().size(), 0);
1293 }
1294 
testOverdue()1295 void MyMoneyXmlContentHandlerTest::testOverdue()
1296 {
1297   MyMoneySchedule sch_overdue;
1298   MyMoneySchedule sch_intime;
1299 
1300   // the following checks only work correctly, if currentDate() is
1301   // between the 1st and 27th. If it is between 28th and 31st
1302   // we don't perform them. Note: this should be fixed.
1303   if (QDate::currentDate().day() > 27 || QDate::currentDate().day() == 1) {
1304     qDebug() << "testOverdue() skipped because current day is between 28th and 2nd";
1305     return;
1306   }
1307 
1308   QDate startDate = QDate::currentDate().addDays(-1).addMonths(-23);
1309   QDate lastPaymentDate = QDate::currentDate().addDays(-1).addMonths(-1);
1310 
1311   QString ref = QString(
1312                   "<!DOCTYPE TEST>\n"
1313                   "<SCHEDULE-CONTAINER>\n"
1314                   " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"0\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"8\" endDate=\"\" type=\"5\" id=\"SCH0002\" name=\"A Name\" fixed=\"0\" occurenceMultiplier=\"1\" occurence=\"32\" >\n" // krazy:exclude=spelling
1315                   "  <PAYMENTS>\n"
1316                   "   <PAYMENT date=\"%3\" />\n"
1317                   "  </PAYMENTS>\n"
1318                   "  <TRANSACTION postdate=\"\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
1319                   "   <SPLITS>\n"
1320                   "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
1321                   "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
1322                   "   </SPLITS>\n"
1323                   "   <KEYVALUEPAIRS>\n"
1324                   "    <PAIR key=\"key\" value=\"value\" />\n"
1325                   "   </KEYVALUEPAIRS>\n"
1326                   "  </TRANSACTION>\n"
1327                   " </SCHEDULED_TX>\n"
1328                   "</SCHEDULE-CONTAINER>\n");
1329   QString ref_overdue = ref.arg(startDate.toString(Qt::ISODate))
1330                         .arg(lastPaymentDate.toString(Qt::ISODate))
1331                         .arg(lastPaymentDate.toString(Qt::ISODate));
1332 
1333   QString ref_intime = ref.arg(startDate.addDays(1).toString(Qt::ISODate))
1334                        .arg(lastPaymentDate.addDays(1).toString(Qt::ISODate))
1335                        .arg(lastPaymentDate.addDays(1).toString(Qt::ISODate));
1336 
1337   QDomDocument doc;
1338   QDomElement node;
1339 
1340   // std::cout << ref_intime << std::endl;
1341   try {
1342     doc.setContent(ref_overdue);
1343     node = doc.documentElement().firstChild().toElement();
1344     sch_overdue = MyMoneyXmlContentHandler::readSchedule(node);
1345     doc.setContent(ref_intime);
1346     node = doc.documentElement().firstChild().toElement();
1347     sch_intime = MyMoneyXmlContentHandler::readSchedule(node);
1348 
1349     QCOMPARE(sch_overdue.isOverdue(), true);
1350     QCOMPARE(sch_intime.isOverdue(), false);
1351 
1352   } catch (const MyMoneyException &) {
1353     QFAIL("Unexpected exception");
1354   }
1355 }
1356 
testNextPayment()1357 void MyMoneyXmlContentHandlerTest::testNextPayment()
1358 /*
1359  * Test for a schedule where a payment hasn't yet been made.
1360  * First payment is in the future.
1361 */
1362 {
1363   MyMoneySchedule sch;
1364   QString future_sched = QString(
1365                            "<!DOCTYPE TEST>\n"
1366                            "<SCHEDULE-CONTAINER>\n"
1367                            "<SCHEDULED_TX startDate=\"2007-02-17\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH000058\" name=\"Car Tax\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"16384\" >\n" // krazy:exclude=spelling
1368                            "  <PAYMENTS/>\n"
1369                            "  <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
1370                            "  <SPLITS>\n"
1371                            "    <SPLIT payee=\"P000044\" reconciledate=\"\" shares=\"-15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"-15000/100\" account=\"A000155\" />\n"
1372                            "    <SPLIT payee=\"\" reconciledate=\"\" shares=\"15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"15000/100\" account=\"A000182\" />\n"
1373                            "  </SPLITS>\n"
1374                            "  <KEYVALUEPAIRS/>\n"
1375                            "  </TRANSACTION>\n"
1376                            "</SCHEDULED_TX>\n"
1377                            "</SCHEDULE-CONTAINER>\n"
1378                          );
1379 
1380   QDomDocument doc;
1381   QDomElement node;
1382   doc.setContent(future_sched);
1383   node = doc.documentElement().firstChild().toElement();
1384 
1385   try {
1386     sch = MyMoneyXmlContentHandler::readSchedule(node);
1387     QCOMPARE(sch.nextPayment(QDate(2007, 2, 14)), QDate(2007, 2, 17));
1388     QCOMPARE(sch.nextPayment(QDate(2007, 2, 17)), QDate(2008, 2, 17));
1389     QCOMPARE(sch.nextPayment(QDate(2007, 2, 18)), QDate(2008, 2, 17));
1390 
1391   } catch (const MyMoneyException &) {
1392     QFAIL("Unexpected exception");
1393   }
1394 }
1395 
testNextPaymentOnLastDayOfMonth()1396 void MyMoneyXmlContentHandlerTest::testNextPaymentOnLastDayOfMonth()
1397 {
1398   MyMoneySchedule sch;
1399   QString future_sched = QString(
1400                            "<!DOCTYPE TEST>\n"
1401                            "<SCHEDULE-CONTAINER>\n"
1402                            "<SCHEDULED_TX startDate=\"2014-10-31\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH000058\" name=\"Car Tax\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"32\" >\n" // krazy:exclude=spelling
1403                            "  <PAYMENTS/>\n"
1404                            "  <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
1405                            "  <SPLITS>\n"
1406                            "    <SPLIT payee=\"P000044\" reconciledate=\"\" shares=\"-15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"-15000/100\" account=\"A000155\" />\n"
1407                            "    <SPLIT payee=\"\" reconciledate=\"\" shares=\"15000/100\" action=\"Withdrawal\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"15000/100\" account=\"A000182\" />\n"
1408                            "  </SPLITS>\n"
1409                            "  <KEYVALUEPAIRS/>\n"
1410                            "  </TRANSACTION>\n"
1411                            "</SCHEDULED_TX>\n"
1412                            "</SCHEDULE-CONTAINER>\n"
1413                          );
1414 
1415   QDomDocument doc;
1416   QDomElement node;
1417   doc.setContent(future_sched);
1418   node = doc.documentElement().firstChild().toElement();
1419 
1420   try {
1421     sch = MyMoneyXmlContentHandler::readSchedule(node);
1422     QDate nextPayment;
1423 
1424     // check for the first payment to happen
1425     nextPayment = sch.nextPayment(QDate(2014, 10, 1));
1426     QCOMPARE(nextPayment, QDate(2014, 10, 31));
1427     sch.setLastPayment(nextPayment);
1428 
1429     QCOMPARE(sch.nextPayment(QDate(2014, 11, 1)), QDate(2014, 11, 30));
1430     QCOMPARE(sch.nextPayment(QDate(2014, 12, 1)), QDate(2014, 12, 31));
1431     QCOMPARE(sch.nextPayment(QDate(2015, 1, 1)), QDate(2015, 1, 31));
1432     QCOMPARE(sch.nextPayment(QDate(2015, 2, 1)), QDate(2015, 2, 28));
1433     QCOMPARE(sch.nextPayment(QDate(2015, 3, 1)), QDate(2015, 3, 31));
1434 
1435     // now check that we also cover leap years
1436     QCOMPARE(sch.nextPayment(QDate(2016, 2, 1)), QDate(2016, 2, 29));
1437     QCOMPARE(sch.nextPayment(QDate(2016, 3, 1)), QDate(2016, 3, 31));
1438 
1439   } catch (const MyMoneyException &) {
1440     QFAIL("Unexpected exception");
1441   }
1442 }
1443 
testPaymentDates()1444 void MyMoneyXmlContentHandlerTest::testPaymentDates()
1445 {
1446   MyMoneySchedule sch;
1447   QString ref_ok = QString(
1448                      "<!DOCTYPE TEST>\n"
1449                      "<SCHEDULE-CONTAINER>\n"
1450 
1451                      "<SCHEDULED_TX startDate=\"2003-12-31\" autoEnter=\"1\" weekendOption=\"0\" lastPayment=\"2006-01-31\" paymentType=\"2\" endDate=\"\" type=\"2\" id=\"SCH000032\" name=\"DSL\" fixed=\"0\" occurenceMultiplier=\"1\" occurence=\"32\" >\n" // krazy:exclude=spelling
1452                      " <PAYMENTS/>\n"
1453                      " <TRANSACTION postdate=\"2006-02-28\" memo=\"\" id=\"\" commodity=\"EUR\" entrydate=\"\" >\n"
1454                      "  <SPLITS>\n"
1455                      "   <SPLIT payee=\"P000076\" reconciledate=\"\" shares=\"1200/100\" action=\"Deposit\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"1200/100\" account=\"A000076\" />\n"
1456                      "   <SPLIT payee=\"\" reconciledate=\"\" shares=\"-1200/100\" action=\"Deposit\" bankid=\"\" number=\"\" reconcileflag=\"0\" memo=\"\" value=\"-1200/100\" account=\"A000009\" />\n"
1457                      "  </SPLITS>\n"
1458                      "  <KEYVALUEPAIRS/>\n"
1459                      " </TRANSACTION>\n"
1460                      "</SCHEDULED_TX>\n"
1461 
1462                      "</SCHEDULE-CONTAINER>\n"
1463                    );
1464 
1465   QDomDocument doc;
1466   QDomElement node;
1467   doc.setContent(ref_ok);
1468   node = doc.documentElement().firstChild().toElement();
1469 
1470   QDate startDate(2006, 1, 28);
1471   QDate endDate(2006, 5, 30);
1472 
1473   try {
1474     sch = MyMoneyXmlContentHandler::readSchedule(node);
1475     QDate nextPayment = sch.nextPayment(startDate);
1476     QList<QDate> list = sch.paymentDates(nextPayment, endDate);
1477     QCOMPARE(list.count(), 3);
1478     QCOMPARE(list[0], QDate(2006, 2, 28));
1479     QCOMPARE(list[1], QDate(2006, 3, 31));
1480     // Would fall on a Sunday so gets moved back to 28th.
1481     QCOMPARE(list[2], QDate(2006, 4, 28));
1482 
1483     // Add tests for each possible occurrence.
1484     // Check how paymentDates is meant to work
1485     // Build a list of expected dates and compare
1486     // Schedule::Occurrence::Once
1487     sch.setOccurrence(Schedule::Occurrence::Once);
1488     startDate.setDate(2009, 1, 1);
1489     endDate.setDate(2009, 12, 31);
1490     sch.setStartDate(startDate);
1491     sch.setNextDueDate(startDate);
1492     list = sch.paymentDates(startDate, endDate);
1493     QCOMPARE(list.count(), 1);
1494     QCOMPARE(list[0], QDate(2009, 1, 1));
1495     // Schedule::Occurrence::Daily
1496     sch.setOccurrence(Schedule::Occurrence::Daily);
1497     startDate.setDate(2009, 1, 1);
1498     endDate.setDate(2009, 1, 5);
1499     sch.setStartDate(startDate);
1500     sch.setNextDueDate(startDate);
1501     list = sch.paymentDates(startDate, endDate);
1502     QCOMPARE(list.count(), 5);
1503     QCOMPARE(list[0], QDate(2009, 1, 1));
1504     QCOMPARE(list[1], QDate(2009, 1, 2));
1505     // Would fall on Saturday so gets moved to 2nd.
1506     QCOMPARE(list[2], QDate(2009, 1, 2));
1507     // Would fall on Sunday so gets moved to 2nd.
1508     QCOMPARE(list[3], QDate(2009, 1, 2));
1509     QCOMPARE(list[4], QDate(2009, 1, 5));
1510     // Schedule::Occurrence::Daily with multiplier 2
1511     sch.setOccurrenceMultiplier(2);
1512     list = sch.paymentDates(startDate.addDays(1), endDate);
1513     QCOMPARE(list.count(), 2);
1514     // Would fall on Sunday so gets moved to 2nd.
1515     QCOMPARE(list[0], QDate(2009, 1, 2));
1516     QCOMPARE(list[1], QDate(2009, 1, 5));
1517     sch.setOccurrenceMultiplier(1);
1518     // Schedule::Occurrence::Weekly
1519     sch.setOccurrence(Schedule::Occurrence::Weekly);
1520     startDate.setDate(2009, 1, 6);
1521     endDate.setDate(2009, 2, 4);
1522     sch.setStartDate(startDate);
1523     sch.setNextDueDate(startDate);
1524     list = sch.paymentDates(startDate, endDate);
1525     QCOMPARE(list.count(), 5);
1526     QCOMPARE(list[0], QDate(2009, 1, 6));
1527     QCOMPARE(list[1], QDate(2009, 1, 13));
1528     QCOMPARE(list[2], QDate(2009, 1, 20));
1529     QCOMPARE(list[3], QDate(2009, 1, 27));
1530     QCOMPARE(list[4], QDate(2009, 2, 3));
1531     // Schedule::Occurrence::EveryOtherWeek
1532     sch.setOccurrence(Schedule::Occurrence::EveryOtherWeek);
1533     startDate.setDate(2009, 2, 5);
1534     endDate.setDate(2009, 4, 3);
1535     sch.setStartDate(startDate);
1536     sch.setNextDueDate(startDate);
1537     list = sch.paymentDates(startDate, endDate);
1538     QCOMPARE(list.count(), 5);
1539     QCOMPARE(list[0], QDate(2009, 2, 5));
1540     QCOMPARE(list[1], QDate(2009, 2, 19));
1541     QCOMPARE(list[2], QDate(2009, 3, 5));
1542     QCOMPARE(list[3], QDate(2009, 3, 19));
1543     QCOMPARE(list[4], QDate(2009, 4, 2));
1544     // Schedule::Occurrence::Fortnightly
1545     sch.setOccurrence(Schedule::Occurrence::Fortnightly);
1546     startDate.setDate(2009, 4, 4);
1547     endDate.setDate(2009, 5, 31);
1548     sch.setStartDate(startDate);
1549     sch.setNextDueDate(startDate);
1550     list = sch.paymentDates(startDate, endDate);
1551     QCOMPARE(list.count(), 4);
1552     // First one would fall on a Saturday and would get moved
1553     // to 3rd which is before start date so is not in list.
1554     // Would fall on a Saturday so gets moved to 17th.
1555     QCOMPARE(list[0], QDate(2009, 4, 17));
1556     // Would fall on a Saturday so gets moved to 1st.
1557     QCOMPARE(list[1], QDate(2009, 5, 1));
1558     // Would fall on a Saturday so gets moved to 15th.
1559     QCOMPARE(list[2], QDate(2009, 5, 15));
1560     // Would fall on a Saturday so gets moved to 29th.
1561     QCOMPARE(list[3], QDate(2009, 5, 29));
1562     // Schedule::Occurrence::EveryHalfMonth
1563     sch.setOccurrence(Schedule::Occurrence::EveryHalfMonth);
1564     startDate.setDate(2009, 6, 1);
1565     endDate.setDate(2009, 8, 11);
1566     sch.setStartDate(startDate);
1567     sch.setNextDueDate(startDate);
1568     list = sch.paymentDates(startDate, endDate);
1569     QCOMPARE(list.count(), 5);
1570     QCOMPARE(list[0], QDate(2009, 6, 1));
1571     QCOMPARE(list[1], QDate(2009, 6, 16));
1572     QCOMPARE(list[2], QDate(2009, 7, 1));
1573     QCOMPARE(list[3], QDate(2009, 7, 16));
1574     // Would fall on a Saturday so gets moved to 31st.
1575     QCOMPARE(list[4], QDate(2009, 7, 31));
1576     // Schedule::Occurrence::EveryThreeWeeks
1577     sch.setOccurrence(Schedule::Occurrence::EveryThreeWeeks);
1578     startDate.setDate(2009, 8, 12);
1579     endDate.setDate(2009, 11, 12);
1580     sch.setStartDate(startDate);
1581     sch.setNextDueDate(startDate);
1582     list = sch.paymentDates(startDate, endDate);
1583     QCOMPARE(list.count(), 5);
1584     QCOMPARE(list[0], QDate(2009, 8, 12));
1585     QCOMPARE(list[1], QDate(2009, 9, 2));
1586     QCOMPARE(list[2], QDate(2009, 9, 23));
1587     QCOMPARE(list[3], QDate(2009, 10, 14));
1588     QCOMPARE(list[4], QDate(2009, 11, 4));
1589     // Schedule::Occurrence::EveryFourWeeks
1590     sch.setOccurrence(Schedule::Occurrence::EveryFourWeeks);
1591     startDate.setDate(2009, 11, 13);
1592     endDate.setDate(2010, 3, 13);
1593     sch.setStartDate(startDate);
1594     sch.setNextDueDate(startDate);
1595     list = sch.paymentDates(startDate, endDate);
1596     QCOMPARE(list.count(), 5);
1597     QCOMPARE(list[0], QDate(2009, 11, 13));
1598     QCOMPARE(list[1], QDate(2009, 12, 11));
1599     QCOMPARE(list[2], QDate(2010, 1, 8));
1600     QCOMPARE(list[3], QDate(2010, 2, 5));
1601     QCOMPARE(list[4], QDate(2010, 3, 5));
1602     // Schedule::Occurrence::EveryThirtyDays
1603     sch.setOccurrence(Schedule::Occurrence::EveryThirtyDays);
1604     startDate.setDate(2010, 3, 19);
1605     endDate.setDate(2010, 7, 19);
1606     sch.setStartDate(startDate);
1607     sch.setNextDueDate(startDate);
1608     list = sch.paymentDates(startDate, endDate);
1609     QCOMPARE(list.count(), 5);
1610     QCOMPARE(list[0], QDate(2010, 3, 19));
1611     // Would fall on a Sunday so gets moved to 16th.
1612     QCOMPARE(list[1], QDate(2010, 4, 16));
1613     QCOMPARE(list[2], QDate(2010, 5, 18));
1614     QCOMPARE(list[3], QDate(2010, 6, 17));
1615     // Would fall on a Saturday so gets moved to 16th.
1616     QCOMPARE(list[4], QDate(2010, 7, 16));
1617     // Schedule::Occurrence::EveryEightWeeks
1618     sch.setOccurrence(Schedule::Occurrence::EveryEightWeeks);
1619     startDate.setDate(2010, 7, 26);
1620     endDate.setDate(2011, 3, 26);
1621     sch.setStartDate(startDate);
1622     sch.setNextDueDate(startDate);
1623     list = sch.paymentDates(startDate, endDate);
1624     QCOMPARE(list.count(), 5);
1625     QCOMPARE(list[0], QDate(2010, 7, 26));
1626     QCOMPARE(list[1], QDate(2010, 9, 20));
1627     QCOMPARE(list[2], QDate(2010, 11, 15));
1628     QCOMPARE(list[3], QDate(2011, 1, 10));
1629     QCOMPARE(list[4], QDate(2011, 3, 7));
1630     // Schedule::Occurrence::EveryOtherMonth
1631     sch.setOccurrence(Schedule::Occurrence::EveryOtherMonth);
1632     startDate.setDate(2011, 3, 14);
1633     endDate.setDate(2011, 11, 20);
1634     sch.setStartDate(startDate);
1635     sch.setNextDueDate(startDate);
1636     list = sch.paymentDates(startDate, endDate);
1637     QCOMPARE(list.count(), 5);
1638     QCOMPARE(list[0], QDate(2011, 3, 14));
1639     // Would fall on a Saturday so gets moved to 13th.
1640     QCOMPARE(list[1], QDate(2011, 5, 13));
1641     QCOMPARE(list[2], QDate(2011, 7, 14));
1642     QCOMPARE(list[3], QDate(2011, 9, 14));
1643     QCOMPARE(list[4], QDate(2011, 11, 14));
1644     // Schedule::Occurrence::EveryThreeMonths
1645     sch.setOccurrence(Schedule::Occurrence::EveryThreeMonths);
1646     startDate.setDate(2011, 11, 15);
1647     endDate.setDate(2012, 11, 19);
1648     sch.setStartDate(startDate);
1649     sch.setNextDueDate(startDate);
1650     list = sch.paymentDates(startDate, endDate);
1651     QCOMPARE(list.count(), 5);
1652     QCOMPARE(list[0], QDate(2011, 11, 15));
1653     QCOMPARE(list[1], QDate(2012, 2, 15));
1654     QCOMPARE(list[2], QDate(2012, 5, 15));
1655     QCOMPARE(list[3], QDate(2012, 8, 15));
1656     QCOMPARE(list[4], QDate(2012, 11, 15));
1657     // Schedule::Occurrence::Quarterly
1658     sch.setOccurrence(Schedule::Occurrence::Quarterly);
1659     startDate.setDate(2012, 11, 20);
1660     endDate.setDate(2013, 11, 23);
1661     sch.setStartDate(startDate);
1662     sch.setNextDueDate(startDate);
1663     list = sch.paymentDates(startDate, endDate);
1664     QCOMPARE(list.count(), 5);
1665     QCOMPARE(list[0], QDate(2012, 11, 20));
1666     QCOMPARE(list[1], QDate(2013, 2, 20));
1667     QCOMPARE(list[2], QDate(2013, 5, 20));
1668     QCOMPARE(list[3], QDate(2013, 8, 20));
1669     QCOMPARE(list[4], QDate(2013, 11, 20));
1670     // Schedule::Occurrence::EveryFourMonths
1671     sch.setOccurrence(Schedule::Occurrence::EveryFourMonths);
1672     startDate.setDate(2013, 11, 21);
1673     endDate.setDate(2015, 3, 23);
1674     sch.setStartDate(startDate);
1675     sch.setNextDueDate(startDate);
1676     list = sch.paymentDates(startDate, endDate);
1677     QCOMPARE(list.count(), 5);
1678     QCOMPARE(list[0], QDate(2013, 11, 21));
1679     QCOMPARE(list[1], QDate(2014, 3, 21));
1680     QCOMPARE(list[2], QDate(2014, 7, 21));
1681     QCOMPARE(list[3], QDate(2014, 11, 21));
1682     // Would fall on a Saturday so gets moved to 20th.
1683     QCOMPARE(list[4], QDate(2015, 3, 20));
1684     // Schedule::Occurrence::TwiceYearly
1685     sch.setOccurrence(Schedule::Occurrence::TwiceYearly);
1686     startDate.setDate(2015, 3, 22);
1687     endDate.setDate(2017, 3, 29);
1688     sch.setStartDate(startDate);
1689     sch.setNextDueDate(startDate);
1690     list = sch.paymentDates(startDate, endDate);
1691     QCOMPARE(list.count(), 4);
1692     // First date would fall on a Sunday which would get moved
1693     // to 20th which is before start date so not in list.
1694     QCOMPARE(list[0], QDate(2015, 9, 22));
1695     QCOMPARE(list[1], QDate(2016, 3, 22));
1696     QCOMPARE(list[2], QDate(2016, 9, 22));
1697     QCOMPARE(list[3], QDate(2017, 3, 22));
1698     // Schedule::Occurrence::Yearly
1699     sch.setOccurrence(Schedule::Occurrence::Yearly);
1700     startDate.setDate(2017, 3, 23);
1701     endDate.setDate(2021, 3, 29);
1702     sch.setStartDate(startDate);
1703     sch.setNextDueDate(startDate);
1704     list = sch.paymentDates(startDate, endDate);
1705     QCOMPARE(list.count(), 5);
1706     QCOMPARE(list[0], QDate(2017, 3, 23));
1707     QCOMPARE(list[1], QDate(2018, 3, 23));
1708     // Would fall on a Saturday so gets moved to 22nd.
1709     QCOMPARE(list[2], QDate(2019, 3, 22));
1710     QCOMPARE(list[3], QDate(2020, 3, 23));
1711     QCOMPARE(list[4], QDate(2021, 3, 23));
1712     // Schedule::Occurrence::EveryOtherYear
1713     sch.setOccurrence(Schedule::Occurrence::EveryOtherYear);
1714     startDate.setDate(2021, 3, 24);
1715     endDate.setDate(2029, 3, 30);
1716     sch.setStartDate(startDate);
1717     sch.setNextDueDate(startDate);
1718     list = sch.paymentDates(startDate, endDate);
1719     QCOMPARE(list.count(), 5);
1720     QCOMPARE(list[0], QDate(2021, 3, 24));
1721     QCOMPARE(list[1], QDate(2023, 3, 24));
1722     QCOMPARE(list[2], QDate(2025, 3, 24));
1723     QCOMPARE(list[3], QDate(2027, 3, 24));
1724     // Would fall on a Saturday so gets moved to 23rd.
1725     QCOMPARE(list[4], QDate(2029, 3, 23));
1726   } catch (const MyMoneyException &) {
1727     QFAIL("Unexpected exception");
1728   }
1729 }
1730 
testHasReferenceTo()1731 void MyMoneyXmlContentHandlerTest::testHasReferenceTo()
1732 {
1733   MyMoneySchedule sch;
1734   QString ref_ok = QString(
1735                      "<!DOCTYPE TEST>\n"
1736                      "<SCHEDULE-CONTAINER>\n"
1737                      " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"1\" weekendOption=\"2\" lastPayment=\"%2\" paymentType=\"1\" endDate=\"\" type=\"1\" id=\"SCH0002\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"4\" >\n" // krazy:exclude=spelling
1738                      "  <PAYMENTS>\n"
1739                      "   <PAYMENT date=\"%3\" />\n"
1740                      "  </PAYMENTS>\n"
1741                      "  <TRANSACTION postdate=\"2001-12-28\" memo=\"Wohnung:Miete\" id=\"\" commodity=\"EUR\" entrydate=\"2003-09-29\" >\n"
1742                      "   <SPLITS>\n"
1743                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" account=\"A000076\" />\n"
1744                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"\" number=\"\" reconcileflag=\"1\" memo=\"\" value=\"-96379/100\" account=\"A000276\" />\n"
1745                      "   </SPLITS>\n"
1746                      "   <KEYVALUEPAIRS>\n"
1747                      "    <PAIR key=\"key\" value=\"value\" />\n"
1748                      "   </KEYVALUEPAIRS>\n"
1749                      "  </TRANSACTION>\n"
1750                      " </SCHEDULED_TX>\n"
1751                      "</SCHEDULE-CONTAINER>\n"
1752                    ).arg(QDate::currentDate().toString(Qt::ISODate))
1753                    .arg(QDate::currentDate().toString(Qt::ISODate))
1754                    .arg(QDate::currentDate().toString(Qt::ISODate));
1755 
1756   QDomDocument doc;
1757   QDomElement node;
1758   doc.setContent(ref_ok);
1759   node = doc.documentElement().firstChild().toElement();
1760 
1761   try {
1762     sch = MyMoneyXmlContentHandler::readSchedule(node);
1763 
1764   } catch (const MyMoneyException &) {
1765     QFAIL("Unexpected exception");
1766   }
1767 
1768   QCOMPARE(sch.hasReferenceTo(QLatin1String("P000001")), true);
1769   QCOMPARE(sch.hasReferenceTo(QLatin1String("A000276")), true);
1770   QCOMPARE(sch.hasReferenceTo(QLatin1String("A000076")), true);
1771   QCOMPARE(sch.hasReferenceTo(QLatin1String("EUR")), true);
1772 }
1773 
testPaidEarlyOneTime()1774 void MyMoneyXmlContentHandlerTest::testPaidEarlyOneTime()
1775 {
1776 // this tries to figure out what's wrong with
1777 // https://bugs.kde.org/show_bug.cgi?id=231029
1778 
1779   MyMoneySchedule sch;
1780   QDate paymentInFuture = QDate::currentDate().addDays(7);
1781 
1782   QString ref_ok = QString(
1783                      "<!DOCTYPE TEST>\n"
1784                      "<SCHEDULE-CONTAINER>\n"
1785                      " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"0\" weekendOption=\"1\" lastPayment=\"%2\" paymentType=\"2\" endDate=\"%3\" type=\"4\" id=\"SCH0042\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"32\" >\n" // krazy:exclude=spelling
1786                      "  <PAYMENTS/>\n"
1787                      "  <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
1788                      "   <SPLITS>\n"
1789                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" id=\"S0001\" account=\"A000076\" />\n"
1790                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"-96379/100\" id=\"S0002\" account=\"A000276\" />\n"
1791                      "   </SPLITS>\n"
1792                      "  </TRANSACTION>\n"
1793                      " </SCHEDULED_TX>\n"
1794                      "</SCHEDULE-CONTAINER>\n"
1795                    ).arg(paymentInFuture.toString(Qt::ISODate))
1796                    .arg(paymentInFuture.toString(Qt::ISODate))
1797                    .arg(paymentInFuture.toString(Qt::ISODate));
1798 
1799   QDomDocument doc;
1800   QDomElement node;
1801   doc.setContent(ref_ok);
1802   node = doc.documentElement().firstChild().toElement();
1803 
1804   try {
1805     sch = MyMoneyXmlContentHandler::readSchedule(node);
1806     QCOMPARE(sch.isFinished(), true);
1807     QCOMPARE(sch.occurrence(), Schedule::Occurrence::Monthly);
1808     QCOMPARE(sch.paymentDates(QDate::currentDate(), QDate::currentDate().addDays(21)).count(), 0);
1809   } catch (const MyMoneyException &) {
1810     QFAIL("Unexpected exception");
1811   }
1812 }
1813 
testReplaceId()1814 void MyMoneyXmlContentHandlerTest::testReplaceId()
1815 {
1816   MyMoneySchedule sch;
1817   QDate paymentInFuture = QDate::currentDate().addDays(7);
1818 
1819   QString ref_ok = QString(
1820                      "<!DOCTYPE TEST>\n"
1821                      "<SCHEDULE-CONTAINER>\n"
1822                      " <SCHEDULED_TX startDate=\"%1\" autoEnter=\"0\" weekendOption=\"1\" lastPayment=\"%2\" paymentType=\"2\" endDate=\"%3\" type=\"4\" id=\"SCH0042\" name=\"A Name\" fixed=\"1\" occurenceMultiplier=\"1\" occurence=\"32\" >\n" // krazy:exclude=spelling
1823                      "  <PAYMENTS/>\n"
1824                      "  <TRANSACTION postdate=\"\" memo=\"\" id=\"\" commodity=\"GBP\" entrydate=\"\" >\n"
1825                      "   <SPLITS>\n"
1826                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"96379/100\" id=\"S0001\" account=\"A000076\" />\n"
1827                      "    <SPLIT payee=\"P000001\" reconciledate=\"\" shares=\"-96379/100\" action=\"Transfer\" number=\"\" reconcileflag=\"2\" memo=\"\" value=\"-96379/100\" id=\"S0002\" account=\"A000276\" />\n"
1828                      "   </SPLITS>\n"
1829                      "  </TRANSACTION>\n"
1830                      " </SCHEDULED_TX>\n"
1831                      "</SCHEDULE-CONTAINER>\n"
1832                    ).arg(paymentInFuture.toString(Qt::ISODate))
1833                    .arg(paymentInFuture.toString(Qt::ISODate))
1834                    .arg(paymentInFuture.toString(Qt::ISODate));
1835 
1836   QDomDocument doc;
1837   QDomElement node;
1838   doc.setContent(ref_ok);
1839   node = doc.documentElement().firstChild().toElement();
1840 
1841   try {
1842     sch = MyMoneyXmlContentHandler::readSchedule(node);
1843     QCOMPARE(sch.transaction().postDate().isValid(), false);
1844     QCOMPARE(sch.transaction().splits()[0].accountId(), QLatin1String("A000076"));
1845     QCOMPARE(sch.transaction().splits()[1].accountId(), QLatin1String("A000276"));
1846     QCOMPARE(sch.replaceId(QLatin1String("A000079"), QLatin1String("A000076")), true);
1847     QCOMPARE(sch.transaction().splits()[0].accountId(), QLatin1String("A000079"));
1848     QCOMPARE(sch.transaction().splits()[1].accountId(), QLatin1String("A000276"));
1849 
1850   } catch (const MyMoneyException &) {
1851     QFAIL("Unexpected exception");
1852   }
1853 
1854 }
1855