|
GnuCash 2.4.99
|
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 }
1.7.4