GnuCash 2.4.99
test-xml-transaction.c
00001 /***************************************************************************
00002  *            test-xml-transaction.c
00003  *
00004  *  Fri Oct  7 21:26:59 2005
00005  *  Copyright  2005  Neil Williams
00006  *  linux@codehelp.co.uk
00007  ****************************************************************************/
00008 /*
00009  *  This program is free software; you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation; either version 2 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program; if not, write to the Free Software
00021  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00022  *  02110-1301, USA.
00023  */
00024 
00025 #include "config.h"
00026 
00027 #include <glib.h>
00028 #include <glib/gstdio.h>
00029 #include <stdlib.h>
00030 #include <unistd.h>
00031 
00032 #include <sys/types.h>
00033 #include <dirent.h>
00034 #include <sys/stat.h>
00035 
00036 #include "../gnc-xml-helper.h"
00037 #include "../gnc-xml.h"
00038 #include <gnc-engine.h>
00039 #include <cashobjects.h>
00040 #include "../sixtp-parsers.h"
00041 
00042 #include "../sixtp-dom-parsers.h"
00043 #include <TransLog.h>
00044 #include "../io-gncxml-gen.h"
00045 
00046 #include <test-stuff.h>
00047 #include <test-engine-stuff.h>
00048 #include <test-file-stuff.h>
00049 #include <unittest-support.h>
00050 
00051 #include <AccountP.h>
00052 #include <Transaction.h>
00053 #include <TransactionP.h>
00054 
00055 static QofBook *book;
00056 
00057 extern gboolean gnc_transaction_xml_v2_testing;
00058 
00059 static xmlNodePtr
00060 find_appropriate_node(xmlNodePtr node, Split *spl)
00061 {
00062     xmlNodePtr mark;
00063 
00064     for (mark = node->xmlChildrenNode; mark; mark = mark->next)
00065     {
00066         gboolean account_guid_good = FALSE;
00067         gboolean amount_good = FALSE;
00068         xmlNodePtr mark2;
00069 
00070         for (mark2 = mark->xmlChildrenNode; mark2; mark2 = mark2->next)
00071         {
00072             if (safe_strcmp((char*)mark2->name, "split:value") == 0)
00073             {
00074                 gnc_numeric *num = dom_tree_to_gnc_numeric(mark2);
00075 
00076                 if (gnc_numeric_equal(*num, xaccSplitGetValue(spl)))
00077                 {
00078                     amount_good = TRUE;
00079                 }
00080 
00081                 g_free(num);
00082             }
00083             else if (safe_strcmp((char*)mark2->name, "split:account") == 0)
00084             {
00085                 GncGUID *accid = dom_tree_to_guid(mark2);
00086                 Account *account = xaccSplitGetAccount (spl);
00087 
00088                 if (guid_equal(accid, xaccAccountGetGUID(account)))
00089                 {
00090                     account_guid_good = TRUE;
00091                 }
00092                 g_free(accid);
00093             }
00094 
00095             if (account_guid_good && amount_good)
00096             {
00097                 return mark;
00098             }
00099         }
00100     }
00101 
00102     return NULL;
00103 }
00104 
00105 static char *
00106 equals_node_val_vs_split_internal(xmlNodePtr node, Split* spl)
00107 {
00108     xmlNodePtr mark;
00109 
00110     for (mark = node->children; mark != NULL; mark = mark->next)
00111     {
00112         if (safe_strcmp((char*)mark->name, "split:id") == 0)
00113         {
00114             GncGUID *id = dom_tree_to_guid(mark);
00115 
00116             if (!guid_equal(id, xaccSplitGetGUID(spl)))
00117             {
00118                 g_free(id);
00119                 return "ids differ";
00120             }
00121             g_free(id);
00122         }
00123         else if (safe_strcmp((char*)mark->name, "split:memo") == 0)
00124         {
00125             char *memo = dom_tree_to_text(mark);
00126 
00127             if (safe_strcmp(memo, xaccSplitGetMemo(spl)) != 0)
00128             {
00129                 g_free(memo);
00130                 return "memos differ";
00131             }
00132             g_free(memo);
00133         }
00134         else if (safe_strcmp((char*)mark->name, "split:reconciled-state") == 0)
00135         {
00136             char *rs = dom_tree_to_text(mark);
00137 
00138             if (rs[0] != xaccSplitGetReconcile(spl))
00139             {
00140                 g_free(rs);
00141                 return "states differ";
00142             }
00143             g_free(rs);
00144         }
00145         else if (safe_strcmp((char*)mark->name, "split:value") == 0)
00146         {
00147             gnc_numeric *num = dom_tree_to_gnc_numeric(mark);
00148             gnc_numeric val = xaccSplitGetValue(spl);
00149 
00150             if (!gnc_numeric_equal(*num, val))
00151             {
00152                 g_free(num);
00153                 return g_strdup_printf ("values differ: %" G_GINT64_FORMAT "/%"
00154                                         G_GINT64_FORMAT " v %" G_GINT64_FORMAT
00155                                         "/%" G_GINT64_FORMAT,
00156                                         (*num).num, (*num).denom,
00157                                         val.num, val.denom);
00158             }
00159             g_free(num);
00160         }
00161         else if (safe_strcmp((char*)mark->name, "split:quantity") == 0)
00162         {
00163             gnc_numeric *num = dom_tree_to_gnc_numeric(mark);
00164             gnc_numeric val = xaccSplitGetAmount(spl);
00165 
00166             if (!gnc_numeric_equal(*num, val))
00167             {
00168                 return g_strdup_printf( "quantities differ under _equal: %"
00169                                         G_GINT64_FORMAT "/%" G_GINT64_FORMAT
00170                                         " v %" G_GINT64_FORMAT "/%"
00171                                         G_GINT64_FORMAT,
00172                                         (*num).num, (*num).denom,
00173                                         val.num, val.denom );
00174             }
00175             if (!gnc_numeric_equal(*num, val))
00176             {
00177                 g_free(num);
00178                 return g_strdup_printf ("quantities differ: %" G_GINT64_FORMAT
00179                                         "/%" G_GINT64_FORMAT " v %"
00180                                         G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
00181                                         (*num).num, (*num).denom,
00182                                         val.num, val.denom);
00183             }
00184             g_free(num);
00185         }
00186         else if (safe_strcmp((char*)mark->name, "split:account") == 0)
00187         {
00188             GncGUID *id = dom_tree_to_guid(mark);
00189             Account *account = xaccSplitGetAccount (spl);
00190 
00191             if (!guid_equal(id, xaccAccountGetGUID(account)))
00192             {
00193                 g_free(id);
00194                 return "accounts differ";
00195             }
00196             g_free(id);
00197         }
00198     }
00199     return NULL;
00200 }
00201 
00202 static char *
00203 equals_node_val_vs_splits(xmlNodePtr node, const Transaction *trn)
00204 {
00205     xmlNodePtr spl_node;
00206     Split *spl_mark;
00207     char *msg;
00208     int i;
00209 
00210     g_return_val_if_fail(node, FALSE);
00211     g_return_val_if_fail(node->xmlChildrenNode, FALSE);
00212 
00213     for (i = 0, spl_mark = xaccTransGetSplit((Transaction*)trn, i);
00214             spl_mark;
00215             i++, spl_mark = xaccTransGetSplit((Transaction*)trn, i))
00216     {
00217         spl_node = find_appropriate_node(node, spl_mark);
00218 
00219         if (!spl_node)
00220         {
00221             g_print( "Split GUID %s", guid_to_string(xaccSplitGetGUID(spl_mark)) );
00222             return "no matching split found";
00223         }
00224 
00225         msg = equals_node_val_vs_split_internal(spl_node, spl_mark);
00226         if (msg != NULL)
00227         {
00228             return msg;
00229         }
00230     }
00231 
00232     return NULL;
00233 }
00234 
00235 static gchar*
00236 node_and_transaction_equal(xmlNodePtr node, Transaction *trn)
00237 {
00238     xmlNodePtr mark;
00239 
00240     while (safe_strcmp ((char*)node->name, "text") == 0)
00241         node = node->next;
00242 
00243     if (!check_dom_tree_version(node, "2.0.0"))
00244     {
00245         return "version wrong.  Not 2.0.0 or not there";
00246     }
00247 
00248     if (!node->name || safe_strcmp((char*)node->name, "gnc:transaction"))
00249     {
00250         return "Name of toplevel node is bad";
00251     }
00252 
00253     for (mark = node->xmlChildrenNode; mark; mark = mark->next)
00254     {
00255         if (safe_strcmp((char*)mark->name, "text") == 0)
00256         {
00257         }
00258         else if (safe_strcmp((char*)mark->name, "trn:id") == 0)
00259         {
00260             if (!equals_node_val_vs_guid(mark, xaccTransGetGUID(trn)))
00261             {
00262                 return "ids differ";
00263             }
00264         }
00265 
00266         /* This test will fail for many splits where the transaction has
00267          * splits in different commodities -- eg, buying or selling a
00268          * stock. jralls 2010-11-02 */
00269         else if (safe_strcmp((char*)mark->name, "trn:currency") == 0)
00270         {
00271 #if 0
00272             if (!equals_node_val_vs_commodity(
00273                         mark, xaccTransGetCurrency(trn), xaccTransGetBook(trn)))
00274             {
00275                 return g_strdup("currencies differ");
00276             }
00277 #endif
00278         }
00279         else if (safe_strcmp((char*)mark->name, "trn:num") == 0)
00280         {
00281             if (!equals_node_val_vs_string(mark, xaccTransGetNum(trn)))
00282             {
00283                 return "nums differ";
00284             }
00285         }
00286         else if (safe_strcmp((char*)mark->name, "trn:date-posted") == 0)
00287         {
00288             if (!equals_node_val_vs_date(mark, xaccTransRetDatePostedTS(trn)))
00289             {
00290                 return "posted dates differ";
00291             }
00292         }
00293         else if (safe_strcmp((char*)mark->name, "trn:date-entered") == 0)
00294         {
00295             if (!equals_node_val_vs_date(mark, xaccTransRetDateEnteredTS(trn)))
00296             {
00297                 return "entered dates differ";
00298             }
00299         }
00300         else if (safe_strcmp((char*)mark->name, "trn:description") == 0)
00301         {
00302             if (!equals_node_val_vs_string(mark, xaccTransGetDescription(trn)))
00303             {
00304                 return "descriptions differ";
00305             }
00306         }
00307         else if (safe_strcmp((char*)mark->name, "trn:slots") == 0)
00308         {
00309             if (!equals_node_val_vs_kvp_frame(mark, xaccTransGetSlots(trn)))
00310             {
00311                 return "slots differ";
00312             }
00313         }
00314         else if (safe_strcmp((char*)mark->name, "trn:splits") == 0)
00315         {
00316             char *msg = equals_node_val_vs_splits (mark, trn);
00317             if (msg != NULL)
00318             {
00319                 return msg;
00320             }
00321         }
00322         else
00323         {
00324             return "unknown node";
00325         }
00326     }
00327 
00328     return NULL;
00329 }
00330 
00331 static void
00332 really_get_rid_of_transaction(Transaction *trn)
00333 {
00334     xaccTransBeginEdit(trn);
00335     xaccTransDestroy(trn);
00336     xaccTransCommitEdit(trn);
00337 }
00338 
00339 struct tran_data_struct
00340 {
00341     Transaction *trn;
00342     Transaction *new_trn;
00343     gnc_commodity *com;
00344     int value;
00345 };
00346 typedef struct tran_data_struct tran_data;
00347 
00348 static gboolean
00349 test_add_transaction(const char *tag, gpointer globaldata, gpointer data)
00350 {
00351     Transaction *trans = data;
00352     tran_data *gdata = (tran_data*)globaldata;
00353     gboolean retval = TRUE;
00354 
00355     xaccTransBeginEdit (trans);
00356     xaccTransSetCurrency (trans, gdata->com);
00357     xaccTransCommitEdit (trans);
00358 
00359     if (!do_test_args(xaccTransEqual(gdata->trn, trans, TRUE, TRUE, TRUE, FALSE),
00360                       "gnc_transaction_sixtp_parser_create",
00361                       __FILE__, __LINE__,
00362                       "%d", gdata->value))
00363         retval = FALSE;
00364 
00365     gdata->new_trn = trans;
00366 
00367     return retval;
00368 }
00369 
00370 static void
00371 test_transaction(void)
00372 {
00373     int i;
00374 
00375     for (i = 0; i < 50; i++)
00376     {
00377         Transaction *ran_trn;
00378         Account *root;
00379         xmlNodePtr test_node;
00380         gnc_commodity *com, *new_com;
00381         gchar *compare_msg;
00382         gchar *filename1;
00383         int fd;
00384 
00385         /* The next line exists for its side effect of creating the
00386          * account tree. */
00387         root = get_random_account_tree(book);
00388         ran_trn = get_random_transaction(book);
00389         new_com = get_random_commodity( book );
00390         if (!ran_trn)
00391         {
00392             failure_args("transaction_xml", __FILE__, __LINE__,
00393                          "get_random_transaction returned NULL");
00394             return;
00395         }
00396 
00397         {
00398             /* xaccAccountInsertSplit can reorder the splits. */
00399             GList * list = g_list_copy(xaccTransGetSplitList (ran_trn));
00400             GList * node = list;
00401             for ( ; node; node = node->next)
00402             {
00403                 Split * s = node->data;
00404                 Account * a = xaccMallocAccount(book);
00405 
00406                 xaccAccountBeginEdit (a);
00407                 xaccAccountSetCommodity( a, new_com );
00408                 xaccAccountSetCommoditySCU (a, xaccSplitGetAmount (s).denom);
00409                 xaccAccountInsertSplit (a, s);
00410                 xaccAccountCommitEdit (a);
00411             }
00412             g_list_free(list);
00413         }
00414 
00415         com = xaccTransGetCurrency (ran_trn);
00416 
00417         test_node = gnc_transaction_dom_tree_create(ran_trn);
00418         if (!test_node)
00419         {
00420             failure_args("transaction_xml", __FILE__, __LINE__,
00421                          "gnc_transaction_dom_tree_create returned NULL");
00422             really_get_rid_of_transaction(ran_trn);
00423             continue;
00424         }
00425 
00426         if ((compare_msg = node_and_transaction_equal(test_node, ran_trn)) !=
00427                 NULL)
00428         {
00429             failure_args("transaction_xml", __FILE__, __LINE__,
00430                          "node and transaction were not equal: %s",
00431                          compare_msg);
00432             xmlElemDump(stdout, NULL, test_node);
00433             printf("\n");
00434             fflush(stdout);
00435             xmlFreeNode(test_node);
00436             really_get_rid_of_transaction(ran_trn);
00437             continue;
00438         }
00439         else
00440         {
00441             success_args("transaction_xml", __FILE__, __LINE__, "%d", i );
00442         }
00443 
00444         filename1 = g_strdup_printf("test_file_XXXXXX");
00445 
00446         fd = g_mkstemp(filename1);
00447 
00448         write_dom_node_to_file(test_node, fd);
00449 
00450         close(fd);
00451 
00452         {
00453             GList * node = xaccTransGetSplitList (ran_trn);
00454             for ( ; node; node = node->next)
00455             {
00456                 Split * s = node->data;
00457                 Account * a1 = xaccSplitGetAccount(s);
00458                 Account * a2 = xaccMallocAccount(book);
00459 
00460                 xaccAccountBeginEdit (a2);
00461                 xaccAccountSetCommoditySCU (a2, xaccAccountGetCommoditySCU (a1));
00462                 xaccAccountSetGUID (a2, xaccAccountGetGUID (a1));
00463                 xaccAccountCommitEdit (a2);
00464             }
00465         }
00466 
00467         {
00468             sixtp *parser;
00469             tran_data data;
00470 
00471             gchar *msg = "[xaccAccountScrubCommodity()] Account \"\" does not have a commodity!";
00472             gchar *logdomain = "gnc.engine.scrub";
00473             guint loglevel = G_LOG_LEVEL_CRITICAL;
00474             TestErrorStruct check = { loglevel, logdomain, msg };
00475             g_log_set_handler (logdomain, loglevel,
00476                                (GLogFunc)test_checked_handler, &check);
00477             data.trn = ran_trn;
00478             data.com = com;
00479             data.value = i;
00480             parser = gnc_transaction_sixtp_parser_create();
00481 
00482             if (!gnc_xml_parse_file(parser, filename1, test_add_transaction,
00483                                     (gpointer)&data, book))
00484             {
00485                 failure_args("gnc_xml_parse_file returned FALSE",
00486                              __FILE__, __LINE__, "%d", i);
00487             }
00488             else
00489                 really_get_rid_of_transaction (data.new_trn);
00490 
00491             /* no handling of circular data structures.  We'll do that later */
00492             /* sixtp_destroy(parser); */
00493         }
00494 
00495         g_unlink(filename1);
00496         g_free(filename1);
00497         really_get_rid_of_transaction(ran_trn);
00498         xmlFreeNode(test_node);
00499     }
00500 }
00501 
00502 static gboolean
00503 test_real_transaction(const char *tag, gpointer global_data, gpointer data)
00504 {
00505     const char *msg;
00506 
00507     msg = node_and_transaction_equal((xmlNodePtr)global_data,
00508                                      (Transaction*)data);
00509     do_test_args(msg == NULL, "test_real_transaction",
00510                  __FILE__, __LINE__, msg);
00511     really_get_rid_of_transaction((Transaction*)data);
00512     return TRUE;
00513 }
00514 
00515 int
00516 main (int argc, char ** argv)
00517 {
00518     qof_init();
00519     cashobjects_register();
00520     xaccLogDisable();
00521 
00522     gnc_transaction_xml_v2_testing = TRUE;
00523 
00524     book = qof_book_new ();
00525 
00526     if (argc > 1)
00527     {
00528         test_files_in_dir(argc, argv, test_real_transaction,
00529                           gnc_transaction_sixtp_parser_create(),
00530                           "gnc:transaction", book);
00531     }
00532     else
00533     {
00534         test_transaction();
00535     }
00536 
00537     print_test_results();
00538     qof_close();
00539     exit(get_rv());
00540 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines