test-book-merge.c

00001 /*********************************************************************
00002  * test-book-merge.c -- test implementation api for QoFBook merge    *
00003  * Copyright (C) 2004-2005 Neil Williams <linux@codehelp.co.uk>      *
00004  *                                                                   *
00005  * This program is free software; you can redistribute it and/or     *
00006  * modify it under the terms of the GNU General Public License as    *
00007  * published by the Free Software Foundation; either version 2 of    *
00008  * the License, or (at your option) any later version.               *
00009  *                                                                   *
00010  * This program is distributed in the hope that it will be useful,   *
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of    *
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the     *
00013  * GNU General Public License for more details.                      *
00014  *                                                                   *
00015  * You should have received a copy of the GNU General Public License *
00016  * along with this program; if not, contact:                         *
00017  *                                                                   *
00018  * Free Software Foundation           Voice:  +1-617-542-5942        *
00019  * 59 Temple Place - Suite 330        Fax:    +1-617-542-2652        *
00020  * Boston, MA  02111-1307,  USA       gnu@gnu.org                    *
00021  *                                                                   *
00022  ********************************************************************/
00023  /* Test the qof_book_merge infrastructure.
00024 
00025  This is an external QOF test routine that cannot use
00026  Gtk, Guile, Scheme or gnc-module handlers. The only
00027  libraries that can be used here are Glib and QOF itself.
00028  */
00029 
00030 #include <glib.h>
00031 #define _GNU_SOURCE
00032 
00033 #include "qof.h"
00034 #include "qofinstance-p.h"
00035 #include "qofevent-p.h"
00036 #include "test-stuff.h"
00037 
00038 #define TEST_MODULE_NAME "book-merge-test"
00039 #define TEST_MODULE_DESC "Test Book Merge"
00040 #define OBJ_NAME "somename"
00041 #define OBJ_AMOUNT "anamount"
00042 #define OBJ_DATE "nottoday"
00043 #define OBJ_GUID "unique"
00044 #define OBJ_DISCOUNT "hefty"
00045 #define OBJ_VERSION "early"
00046 #define OBJ_MINOR "tiny"
00047 #define OBJ_ACTIVE "ofcourse"
00048 #define OBJ_FLAG   "tiny_flag"
00049 
00050 static void test_rule_loop (QofBookMergeData*, QofBookMergeRule*, guint);
00051 static void test_merge (void);
00052 gboolean myobjRegister (void);
00053 
00054 /* simple object structure */
00055 typedef struct obj_s
00056 {
00057         QofInstance inst;
00058         char            *Name;
00059         char            flag;
00060         gnc_numeric Amount;
00061         const GUID      *obj_guid;
00062         Timespec        date;
00063         double          discount; /* cheap pun, I know. */
00064         gboolean        active;
00065         gint32          version;
00066         gint64          minor;
00067 }myobj;
00068 
00069 myobj* obj_create(QofBook*);
00070 
00071 /* obvious setter functions */
00072 void obj_setName(myobj*,        char*);
00073 void obj_setGUID(myobj*,        const GUID*);
00074 void obj_setAmount(myobj*,  gnc_numeric);
00075 void obj_setDate(myobj*,        Timespec h);
00076 void obj_setDiscount(myobj*, double);
00077 void obj_setActive(myobj*,  gboolean);
00078 void obj_setVersion(myobj*, gint32);
00079 void obj_setMinor(myobj*,   gint64);
00080 void obj_setFlag(myobj*, char);
00081 
00082 /* obvious getter functions */
00083 char*           obj_getName(myobj*);
00084 const GUID*     obj_getGUID(myobj*);
00085 gnc_numeric obj_getAmount(myobj*);
00086 Timespec        obj_getDate(myobj*);
00087 double          obj_getDiscount(myobj*);
00088 gboolean        obj_getActive(myobj*);
00089 gint32          obj_getVersion(myobj*);
00090 gint64          obj_getMinor(myobj*);
00091 char            obj_getFlag(myobj*);
00092 
00093 myobj*
00094 obj_create(QofBook *book)
00095 {
00096         myobj *g;
00097         g_return_val_if_fail(book, NULL);
00098         g = g_new(myobj, 1);
00099         qof_instance_init (&g->inst, TEST_MODULE_NAME, book);
00100         obj_setGUID(g,qof_instance_get_guid(&g->inst));
00101         g->date.tv_nsec = 0;
00102         g->date.tv_sec = 0;
00103         g->discount = 0;
00104         g->active = TRUE;
00105         g->version = 1;
00106         g->minor = 1;
00107         g->flag = 'n';
00108         qof_event_gen(&g->inst.entity, QOF_EVENT_CREATE, NULL);
00109         return g;
00110 }
00111 
00112 void
00113 obj_setFlag(myobj *g, char f)
00114 {
00115         g_return_if_fail(g);
00116         g->flag = f;
00117 }
00118 
00119 char
00120 obj_getFlag(myobj *g)
00121 {
00122         g_return_val_if_fail(g, 'n');
00123         return g->flag;
00124 }
00125 
00126 void
00127 obj_setMinor(myobj *g, gint64 h)
00128 {
00129         g_return_if_fail(g != NULL);
00130         g->minor = h;
00131 }
00132 
00133 gint64
00134 obj_getMinor(myobj *g)
00135 {
00136         g_return_val_if_fail((g != NULL),0);
00137         return g->minor;
00138 }
00139 
00140 void
00141 obj_setVersion(myobj *g, gint32 h)
00142 {
00143         g_return_if_fail(g != NULL);
00144         g->version = h;
00145 }
00146 
00147 gint32
00148 obj_getVersion(myobj *g)
00149 {
00150         if(!g) return 0;
00151         return g->version;
00152 }
00153 
00154 void
00155 obj_setActive(myobj *g, gboolean h)
00156 {
00157         if(!g) return;
00158         g->active = h;
00159 }
00160 
00161 gboolean
00162 obj_getActive(myobj *g)
00163 {
00164         if(!g) return FALSE;
00165         return g->active;
00166 }
00167 
00168 void
00169 obj_setDiscount(myobj *g, double h)
00170 {
00171         if(!g) return;
00172         g->discount = h;
00173 }
00174 
00175 double
00176 obj_getDiscount(myobj *g)
00177 {
00178         if(!g) return 0;
00179         return g->discount;
00180 }
00181 
00182 void
00183 obj_setDate(myobj *g, Timespec h)
00184 {
00185         if(!g) return;
00186         g->date = h;
00187 }
00188 
00189 Timespec
00190 obj_getDate(myobj *g)
00191 {
00192         Timespec ts;
00193         ts.tv_sec = 0;
00194         ts.tv_nsec = 0;
00195         if(!g) return ts;
00196         ts = g->date;
00197         return ts;
00198 }
00199 
00200 void
00201 obj_setGUID(myobj* g, const GUID* h)
00202 {
00203         if(!g) return;
00204         g->obj_guid = h;
00205 }
00206 
00207 const GUID*
00208 obj_getGUID(myobj *g)
00209 {
00210         if(!g) return NULL;
00211         return g->obj_guid;
00212 }
00213 
00214 void
00215 obj_setName(myobj* g, char* h)
00216 {
00217         if(!g || !h) return;
00218         g->Name = strdup(h);
00219 }
00220 
00221 char*
00222 obj_getName(myobj *g)
00223 {
00224         if(!g) return NULL;
00225         return g->Name;
00226 }
00227 
00228 void
00229 obj_setAmount(myobj *g, gnc_numeric h)
00230 {
00231         if(!g) return;
00232         g->Amount = h;
00233 }
00234 
00235 gnc_numeric
00236 obj_getAmount(myobj *g)
00237 {
00238         if(!g) return gnc_numeric_zero();
00239         return g->Amount;
00240 }
00241 
00242 static QofObject obj_object_def = {
00243   interface_version:     QOF_OBJECT_VERSION,
00244   e_type:                TEST_MODULE_NAME,
00245   type_label:            TEST_MODULE_DESC,
00246   create:                (gpointer)obj_create,
00247   book_begin:            NULL,
00248   book_end:              NULL,
00249   is_dirty:              NULL,
00250   mark_clean:            NULL,
00251   foreach:               qof_collection_foreach,
00252   printable:             NULL,
00253   version_cmp:           (gint (*)(gpointer,gpointer)) qof_instance_version_cmp,
00254 };
00255 
00256 gboolean myobjRegister (void)
00257 {
00258   static QofParam params[] = {
00259         { OBJ_NAME,     QOF_TYPE_STRING,  (QofAccessFunc)obj_getName, 
00260                 (QofSetterFunc)obj_setName },
00261         { OBJ_AMOUNT,   QOF_TYPE_NUMERIC, (QofAccessFunc)obj_getAmount,
00262                 (QofSetterFunc)obj_setAmount },
00263         { OBJ_GUID,     QOF_TYPE_GUID,    (QofAccessFunc)obj_getGUID,   
00264                 (QofSetterFunc)obj_setGUID },
00265         { OBJ_DATE,     QOF_TYPE_DATE,    (QofAccessFunc)obj_getDate,   
00266                 (QofSetterFunc)obj_setDate },
00267         { OBJ_DISCOUNT, QOF_TYPE_DOUBLE,  (QofAccessFunc)obj_getDiscount, 
00268                 (QofSetterFunc)obj_setDiscount },
00269         { OBJ_ACTIVE,   QOF_TYPE_BOOLEAN, (QofAccessFunc)obj_getActive,   
00270                 (QofSetterFunc)obj_setActive },
00271         { OBJ_VERSION,  QOF_TYPE_INT32,   (QofAccessFunc)obj_getVersion,  
00272                 (QofSetterFunc)obj_setVersion },
00273         { OBJ_MINOR,    QOF_TYPE_INT64,   (QofAccessFunc)obj_getMinor,  
00274                 (QofSetterFunc)obj_setMinor },
00275         { OBJ_FLAG,     QOF_TYPE_CHAR,    (QofAccessFunc)obj_getFlag,
00276                 (QofSetterFunc)obj_setFlag },
00277     { QOF_PARAM_BOOK, QOF_ID_BOOK,      (QofAccessFunc)qof_instance_get_book, NULL },
00278     { QOF_PARAM_GUID, QOF_TYPE_GUID,    (QofAccessFunc)qof_instance_get_guid, NULL },
00279     { NULL },
00280   };
00281 
00282   qof_class_register (TEST_MODULE_NAME, NULL, params);
00283 
00284   return qof_object_register (&obj_object_def);
00285 }
00286 
00287 static void
00288 test_merge (void)
00289 {
00290         QofBook *target, *import;
00291         double init_value, discount;
00292         myobj *import_obj, *target_obj, *new_obj;
00293         int result;
00294         Timespec ts, tc;
00295         gboolean active;
00296         gint32 version;
00297         gint64 minor;
00298         gchar *import_init, *target_init;
00299         gchar flag, flag_check;
00300         gnc_numeric obj_amount;
00301         QofBookMergeData *mergeData;
00302 
00303         target = qof_book_new();
00304         import = qof_book_new();
00305         init_value = 1.00;
00306         result = 0;
00307         flag = get_random_character();
00308         discount = get_random_double();
00309         active = TRUE;
00310         version = get_random_int_in_range(0,10000);
00311         minor = get_random_int_in_range(1000001,2000000);
00312         import_init = "test";
00313         target_init = "testing";
00314         qof_date_format_set(QOF_DATE_FORMAT_UK);
00315         timespecFromTime_t(&ts,time(NULL));
00316 
00317         do_test ((NULL != target), "#1 target book is NULL");
00318 
00319         /* import book objects - tests used */
00320         do_test ((NULL != import), "#2 import book is NULL");
00321         import_obj = g_new(myobj, 1);
00322         do_test ((NULL != import_obj), "#3 new object create");
00323         qof_instance_init (&import_obj->inst, TEST_MODULE_NAME, import);
00324         do_test ((NULL != &import_obj->inst), "#4 instance init");
00325         obj_setGUID(import_obj,qof_instance_get_guid(&import_obj->inst));
00326         do_test ((NULL != &import_obj->obj_guid), "#5 guid set");
00327         gnc_engine_gen_event(&import_obj->inst.entity, GNC_EVENT_CREATE);
00328         do_test ((NULL != &import_obj->inst.entity), "#6 gnc event create");
00329         obj_setName(import_obj, import_init);
00330         do_test ((NULL != &import_obj->Name), "#7 string set");
00331         obj_amount = double_to_gnc_numeric(init_value,1, GNC_HOW_DENOM_EXACT);
00332         obj_setAmount(import_obj, obj_amount);
00333         do_test ((gnc_numeric_check(obj_getAmount(import_obj)) == GNC_ERROR_OK), 
00334                 "#8 gnc_numeric set");
00335         obj_setActive(import_obj, active);
00336         do_test ((FALSE != &import_obj->active), "#9 gboolean set");
00337         obj_setDiscount(import_obj, discount);
00338         do_test ((discount == import_obj->discount), "#10 double set");
00339         obj_setVersion(import_obj, version);
00340         do_test ((version == import_obj->version), "#11 gint32 set");
00341         obj_setMinor(import_obj, minor);
00342         do_test ((minor == import_obj->minor), "#12 gint64 set");
00343         obj_setDate(import_obj, ts );
00344         tc = import_obj->date;
00345         do_test ((timespec_cmp(&ts, &tc) == 0), "#13 date set");
00346         obj_setFlag(import_obj, flag);
00347         do_test ((flag == obj_getFlag(import_obj)), "#14 flag set");
00348 
00349         obj_amount = gnc_numeric_add(obj_amount, obj_amount, 1, GNC_HOW_DENOM_EXACT);
00350         discount = get_random_double();
00351         version = 2;
00352         minor = 3;
00353 
00354         /* second import object - test results would be the same, so not tested. */
00355         new_obj = g_new(myobj, 1);
00356         qof_instance_init (&new_obj->inst, TEST_MODULE_NAME, import);
00357         obj_setGUID(new_obj,qof_instance_get_guid(&new_obj->inst));
00358         qof_event_gen (&new_obj->inst.entity, GNC_EVENT_CREATE, NULL);
00359         obj_setName(new_obj, import_init);
00360         obj_setAmount(new_obj, obj_amount);
00361         obj_setActive(new_obj, active);
00362         obj_setDiscount(new_obj, discount);
00363         obj_setVersion(new_obj, version);
00364         obj_setMinor(new_obj, minor);
00365         obj_setDate(new_obj, ts);
00366         obj_setFlag(new_obj, flag);
00367 
00368         obj_amount = gnc_numeric_add(obj_amount, obj_amount, 1, GNC_HOW_DENOM_EXACT);
00369         discount = get_random_double();
00370         version = 2;
00371         minor = 3;
00372         flag = 'z';
00373         tc.tv_sec = ts.tv_sec -1;
00374         tc.tv_nsec = 0;
00375 
00376         /* target object - test results would be the same, so not tested. */
00377         target_obj = g_new(myobj, 1);
00378         qof_instance_init (&target_obj->inst, TEST_MODULE_NAME, target);
00379         obj_setGUID(target_obj,qof_instance_get_guid(&target_obj->inst));
00380         qof_event_gen (&target_obj->inst.entity, GNC_EVENT_CREATE, NULL);
00381         obj_setName(target_obj, target_init);
00382         obj_setAmount(target_obj, obj_amount);
00383         obj_setActive(target_obj, active);
00384         obj_setDiscount(target_obj, discount);
00385         obj_setVersion(target_obj, version);
00386         obj_setMinor(target_obj, minor);
00387         obj_setDate(target_obj, tc );
00388         obj_setFlag(target_obj, flag);
00389         do_test ((flag == obj_getFlag(target_obj)), "#15 flag set");
00390 
00391         mergeData = qof_book_merge_init(import, target);
00392         do_test ( mergeData != NULL, "FATAL: Merge could not be initialised!\t aborting . . ");
00393         g_return_if_fail(mergeData != NULL);
00394         qof_book_merge_rule_foreach(mergeData, test_rule_loop, MERGE_REPORT);
00395         qof_book_merge_rule_foreach(mergeData, test_rule_loop, MERGE_UPDATE);
00396         qof_book_merge_rule_foreach(mergeData, test_rule_loop, MERGE_NEW);
00397         /* reserved calls - test only */
00398         qof_book_merge_rule_foreach(mergeData, test_rule_loop, MERGE_ABSOLUTE);
00399         qof_book_merge_rule_foreach(mergeData, test_rule_loop, MERGE_DUPLICATE);
00400 
00401         /* import should not be in the target - pass if import_init fails match with target */
00402         do_test (((safe_strcmp(obj_getName(import_obj),obj_getName(target_obj))) != 0), 
00403                 "Init value test #1");
00404 
00405         /* a good commit returns zero */
00406         do_test (qof_book_merge_commit(mergeData) == 0, "Commit failed");
00407 
00408         /* import should be in the target - pass if import_init matches target */
00409         do_test (((safe_strcmp(import_init,obj_getName(target_obj))) == 0), 
00410                 "Merged value test #1");
00411 
00412         /* import should be the same as target - pass if values are the same */
00413         do_test (((safe_strcmp(obj_getName(target_obj),obj_getName(import_obj))) == 0), 
00414                 "Merged value test #2");
00415 
00416         /* check that the Amount really is a gnc_numeric */
00417         do_test ((gnc_numeric_check(obj_getAmount(import_obj)) == GNC_ERROR_OK), 
00418                 "import gnc_numeric check");
00419         do_test ((gnc_numeric_check(obj_getAmount(target_obj)) == GNC_ERROR_OK), 
00420                 "target gnc_numeric check");
00421 
00422         /* obj_amount was changed after the import object was set, so expect a difference. */
00423         do_test ((gnc_numeric_compare(obj_getAmount(import_obj), obj_amount) != GNC_ERROR_OK),
00424                 "gnc_numeric value check #1");
00425 
00426         /* obj_amount is in the target object with the import value, expect a difference/ */
00427         do_test ((gnc_numeric_compare(obj_getAmount(target_obj), obj_amount) != GNC_ERROR_OK),
00428                 "gnc_numeric value check #2");
00429 
00430         /* target had a different date, so import date should now be set */
00431         tc = target_obj->date;
00432         do_test ((timespec_cmp(&ts, &tc) == 0), "date value check: 1");
00433         tc = import_obj->date;
00434         do_test ((timespec_cmp(&tc, &ts) == 0), "date value check: 2");
00435         do_test ((timespec_cmp(&import_obj->date, &target_obj->date) == 0), 
00436                 "date value check: 3");
00437 
00438         /* import should be the same as target - pass if values are the same */
00439         flag_check = obj_getFlag(target_obj);
00440         do_test ((flag_check == obj_getFlag(import_obj)), "flag value check: 1");
00441         do_test ((obj_getFlag(import_obj) == obj_getFlag(target_obj)), 
00442                 "flag value check: 2");
00443 }
00444 
00445 static void
00446 test_rule_loop (QofBookMergeData *mergeData, QofBookMergeRule *rule, guint remainder)
00447 {
00448         GSList *testing;
00449         QofParam *eachParam;
00450         char *importstring;
00451         char *targetstring;
00452         gboolean skip_target;
00453 
00454         importstring = NULL;
00455         targetstring = NULL;
00456         skip_target = FALSE;
00457         mergeData->currentRule = rule;
00458         do_test ((rule != NULL), "loop:#1 Rule is NULL");
00459         do_test (remainder > 0, "loop:#2 remainder error.");
00460         do_test ((safe_strcmp(NULL, rule->mergeLabel) != 0), "loop:#3 object label\n");
00461         do_test ((rule->importEnt != NULL), "loop:#4 empty import entity");
00462         /* targetEnt is always NULL at this stage if MERGE_NEW is set */
00463         if(rule->targetEnt == NULL) { skip_target = TRUE; }
00464         if(!skip_target) {
00465                 do_test ((safe_strcmp(rule->importEnt->e_type, rule->targetEnt->e_type) == 0),
00466                         "loop: entity type mismatch");
00467         }
00468         do_test ((rule->mergeParam != NULL), "loop: empty parameter list");
00469         testing = rule->mergeParam;
00470 
00471         while(testing != NULL) { // start of param loop
00472                 eachParam = testing->data;
00473                 do_test ((eachParam != NULL), "loop:#8 no QofParam data");
00474                 do_test ((eachParam->param_name != NULL), "loop:#9 no parameter name");
00475                 do_test ((eachParam->param_getfcn != NULL), "loop:#10 no get function");
00476                 do_test ((eachParam->param_setfcn != NULL), "loop:#11 no set function");
00477                 /* non-generic - test routines only! */
00478                 if(safe_strcmp(eachParam->param_type, QOF_TYPE_STRING) == 0) {
00479                         importstring = g_strdup(eachParam->param_getfcn(rule->importEnt, eachParam));
00480                         do_test ((importstring != NULL), "loop:#12 direct get_fcn import");
00481                         do_test ((safe_strcmp(importstring, "test") == 0), "loop:#13 direct import comparison");
00482                         if(!skip_target) {
00483                         targetstring = eachParam->param_getfcn(rule->targetEnt, eachParam);
00484                         do_test ((targetstring != NULL), "loop:#14 direct get_fcn target");
00485                         do_test ((safe_strcmp(targetstring, "testing") == 0), "loop:#15 direct target comparison");
00486                 }
00487                 }
00488                 /* param_as_string does the conversion for display purposes only */
00489                 /* do NOT use as_string for calculations or set_fcn */
00490                 importstring = qof_book_merge_param_as_string(eachParam, rule->importEnt);
00491                 do_test ((importstring != NULL), "loop:#16 import param_as_string is null");
00492                 if(!skip_target) {
00493                 targetstring = qof_book_merge_param_as_string(eachParam, rule->targetEnt);
00494                 do_test ((targetstring != NULL), "loop:#17 target param_as_string is null");
00495                         }
00496                 testing = g_slist_next(testing);
00497         } // end param loop
00498         /* set each rule dependent on the user involvement response above. */
00499         /* test routine just sets all MERGE_REPORT to MERGE_UPDATE */
00500         mergeData = qof_book_merge_update_result(mergeData, MERGE_UPDATE);
00501         do_test ((rule->mergeResult != MERGE_REPORT), "update result fail");
00502 }
00503 
00504 int
00505 main (int argc, const char *argv[])
00506 {
00507         qof_init();
00508         myobjRegister();
00509         test_merge();
00510         print_test_results();
00511         qof_close();
00512         return 0;
00513 }

Generated on Fri May 12 18:00:33 2006 for QOF by  doxygen 1.4.4