GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
test-engine-stuff.c
Go to the documentation of this file.
1 
18 #include "config.h"
19 
20 #include <sys/types.h>
21 #include <dirent.h>
22 #include <fcntl.h>
23 #include <glib.h>
24 #include <stdio.h>
25 #include <stdint.h>
26 #include <inttypes.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31 #include <qofinstance-p.h>
32 
33 #include "Account.h"
34 #include "AccountP.h"
35 #include "gnc-engine.h"
36 #include "gnc-session.h"
37 #include "Transaction.h"
38 #include "TransactionP.h"
39 #include "Recurrence.h"
40 #include "SchedXaction.h"
41 #include "SX-book.h"
42 
43 #include "test-engine-stuff.h"
44 #include "test-stuff.h"
45 #include "test-engine-strings.h"
46 
47 static gboolean glist_strings_only = FALSE;
48 
49 static GHashTable *exclude_kvp_types = NULL;
50 static gint kvp_max_depth = 5;
51 static gint kvp_frame_max_elements = 10;
52 
53 static gint max_tree_depth = 1;
54 static gint max_level_accounts = 3;
55 static gint max_total_accounts = 10;
56 static gint max_trans_num = 1000;
57 static gint total_num_accounts = 0;
58 /* SCU == smallest currency unit -- the value of the denominator */
59 static gint max_scu = 100; //6000;
60 static gint min_scu = 100; //1;
61 static const int64_t num_limit = INT64_MAX; //1E19+
62 static const int64_t max_denom_mult = 1000000LL; //1E6
63 
64 
65 /* The inverse fraction of split/transaction data that should
66  * contain invalid/inconsistent fields/values. Thus,
67  * if borked==1000, then one in 1000 fields will have bad data.
68  * This is used to test the data integrity scrubbers, which are
69  * supposed to clean up any crud they find.
70  */
71 static gint borked = 80;
72 
73 gboolean gnc_engine_debug_random = FALSE;
74 
75 /* ========================================================== */
76 /* Set control parameters governing the run. */
77 
78 void
79 set_max_account_tree_depth (gint max_tree_depth_in)
80 {
81  max_tree_depth = MAX (max_tree_depth_in, 1);
82 }
83 
84 void
85 set_max_accounts_per_level (gint max_level_accounts_in)
86 {
87  max_level_accounts = MAX (max_level_accounts_in, 1);
88 }
89 
90 void
91 set_max_kvp_depth (gint max_kvp_depth)
92 {
93  kvp_max_depth = MAX (max_kvp_depth, 1);
94 }
95 
96 void
97 set_max_kvp_frame_elements (gint max_kvp_frame_elements)
98 {
99  kvp_frame_max_elements = MAX (max_kvp_frame_elements, 1);
100 }
101 
102 void
103 kvp_exclude_type (KvpValueType kvp_type)
104 {
105  gint *key;
106 
107  if (!exclude_kvp_types)
108  exclude_kvp_types = g_hash_table_new (g_int_hash, g_int_equal);
109 
110  key = g_new (gint, 1);
111  *key = kvp_type;
112 
113  g_hash_table_insert (exclude_kvp_types, key, exclude_kvp_types);
114 }
115 
116 static gboolean
117 kvp_type_excluded (KvpValueType kvp_type)
118 {
119  gint key = kvp_type;
120 
121  if (!exclude_kvp_types)
122  return FALSE;
123 
124  if (g_hash_table_lookup (exclude_kvp_types, &key))
125  return TRUE;
126 
127  return FALSE;
128 }
129 
130 void
131 random_glist_strings_only (gboolean strings_only)
132 {
133  glist_strings_only = strings_only;
134 }
135 
136 static gboolean zero_nsec = FALSE;
137 
138 void
139 random_timespec_zero_nsec (gboolean zero_nsec_in)
140 {
141  zero_nsec = zero_nsec_in;
142 }
143 
144 static gboolean usec_resolution = FALSE;
145 
146 void
147 random_timespec_usec_resolution (gboolean usec_resolution_in)
148 {
149  usec_resolution = usec_resolution_in;
150 }
151 
152 /* ========================================================== */
153 
154 static inline gboolean
155 do_bork (void)
156 {
157  if (1 == get_random_int_in_range (0, borked))
158  {
159  return TRUE;
160  }
161  return FALSE;
162 }
163 
164 /* ========================================================== */
165 /* GList stuff */
166 
167 static gpointer
168 get_random_list_element (GList *list)
169 {
170  g_return_val_if_fail (list, NULL);
171 
172  return g_list_nth_data (list,
173  get_random_int_in_range (0,
174  g_list_length (list) - 1));
175 }
176 
177 static KvpValue* get_random_kvp_value_depth (int type, gint depth);
178 
179 static GList*
180 get_random_glist_depth (gint depth)
181 {
182  GList *ret = NULL;
183  int count = get_random_int_in_range(1, 5);
184  int i;
185 
186  if (depth >= kvp_max_depth)
187  return NULL;
188 
189  for (i = 0; i < count; i++)
190  {
191  KvpValueType kvpt;
192  KvpValue *value;
193 
194  kvpt = glist_strings_only ? KVP_TYPE_STRING : -2;
195 
196  do
197  {
198  value = get_random_kvp_value_depth (kvpt, depth + 1);
199  }
200  while (!value);
201 
202  ret = g_list_prepend(ret, value);
203  }
204 
205  return ret;
206 }
207 
208 GList*
209 get_random_glist(void)
210 {
211  return get_random_glist_depth (0);
212 }
213 
214 /* ========================================================== */
215 /* Time/Date, GncGUID data stuff */
216 
217 Timespec*
218 get_random_timespec(void)
219 {
220  Timespec *ret;
221 
222  ret = g_new0(Timespec, 1);
223 
224  while (ret->tv_sec <= 0)
225  ret->tv_sec = rand();
226 
227  if (zero_nsec)
228  ret->tv_nsec = 0;
229  else
230  {
231  ret->tv_nsec = rand();
232 
233  if (usec_resolution)
234  {
235  ret->tv_nsec = MIN (ret->tv_nsec, 999999999);
236  ret->tv_nsec /= 1000;
237  ret->tv_nsec *= 1000;
238  }
239  }
240 
241  return ret;
242 }
243 
244 GncGUID*
245 get_random_guid(void)
246 {
247  GncGUID *ret;
248 
249  ret = g_new(GncGUID, 1);
250  guid_replace(ret);
251 
252  return ret;
253 }
254 
255 /* ========================================================== */
256 /* KVP stuff */
257 
258 static KvpFrame* get_random_kvp_frame_depth (gint depth);
259 
260 static KvpValue*
261 get_random_kvp_value_depth (int type, gint depth)
262 {
263  int datype = type;
264  KvpValue *ret;
265 
266  if (datype == -1)
267  {
268  datype = get_random_int_in_range(KVP_TYPE_GINT64, KVP_TYPE_FRAME);
269  }
270 
271  if (datype == -2)
272  {
273  datype = get_random_int_in_range(KVP_TYPE_GINT64, KVP_TYPE_FRAME - 1);
274  }
275 
276  if (datype == KVP_TYPE_FRAME && depth >= kvp_max_depth)
277  return NULL;
278 
279  if (datype == KVP_TYPE_GLIST && depth >= kvp_max_depth)
280  return NULL;
281 
282  if (kvp_type_excluded (datype))
283  return NULL;
284 
285  switch (datype)
286  {
287  case KVP_TYPE_GINT64:
288  ret = kvp_value_new_gint64(get_random_gint64());
289  break;
290 
291  case KVP_TYPE_DOUBLE:
292  ret = NULL;
293  break;
294 
295  case KVP_TYPE_NUMERIC:
296  ret = kvp_value_new_gnc_numeric(get_random_gnc_numeric(GNC_DENOM_AUTO));
297  break;
298 
299  case KVP_TYPE_STRING:
300  {
301  gchar *tmp_str;
302  tmp_str = get_random_string();
303  if (!tmp_str)
304  return NULL;
305 
306  ret = kvp_value_new_string(tmp_str);
307  g_free(tmp_str);
308  }
309  break;
310 
311  case KVP_TYPE_GUID:
312  {
313  GncGUID *tmp_guid;
314  tmp_guid = get_random_guid();
315  ret = kvp_value_new_guid(tmp_guid);
316  g_free(tmp_guid);
317  }
318  break;
319 
320  case KVP_TYPE_TIMESPEC:
321  {
322  Timespec *ts = get_random_timespec();
323  ret = kvp_value_new_timespec (*ts);
324  g_free(ts);
325  }
326  break;
327 
328  case KVP_TYPE_GLIST:
329  ret = kvp_value_new_glist_nc(get_random_glist_depth (depth + 1));
330  break;
331 
332  case KVP_TYPE_FRAME:
333  {
334  KvpFrame *tmp_frame;
335  tmp_frame = get_random_kvp_frame_depth(depth + 1);
336  ret = kvp_value_new_frame(tmp_frame);
337  kvp_frame_delete(tmp_frame);
338  }
339  break;
340 
341  default:
342  ret = NULL;
343  break;
344  }
345  return ret;
346 }
347 
348 static KvpFrame*
349 get_random_kvp_frame_depth (gint depth)
350 {
351  KvpFrame *ret;
352  int vals_to_add;
353  gboolean val_added;
354 
355  if (depth >= kvp_max_depth)
356  return NULL;
357 
358  ret = kvp_frame_new();
359 
360  vals_to_add = get_random_int_in_range(1, kvp_frame_max_elements);
361  val_added = FALSE;
362 
363  for (; vals_to_add > 0; vals_to_add--)
364  {
365  gchar *key;
366  KvpValue *val;
367 
368  key = NULL;
369  while (key == NULL)
370  {
371  key = get_random_string_without("/");
372  if (*key == '\0')
373  {
374  g_free(key);
375  key = NULL;
376  }
377  }
378 
379  val = get_random_kvp_value_depth (-1, depth + 1);
380  if (!val)
381  {
382  g_free(key);
383  if (!val_added)
384  vals_to_add++;
385  continue;
386  }
387 
388  val_added = TRUE;
389 
390  kvp_frame_set_slot_nc(ret, key, val);
391 
392  g_free(key);
393  }
394 
395  return ret;
396 }
397 
398 KvpFrame *
399 get_random_kvp_frame (void)
400 {
401  return get_random_kvp_frame_depth (0);
402 }
403 
404 KvpValue *
405 get_random_kvp_value(int type)
406 {
407  return get_random_kvp_value_depth (type, 0);
408 }
409 
410 /* ================================================================= */
411 /* Numeric stuff */
412 
413 #define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX)
414 
416 get_random_gnc_numeric(int64_t deno)
417 {
418  gint64 numer;
419  int64_t limit;
420  if (deno == GNC_DENOM_AUTO)
421  {
422  if (RAND_MAX / 8 > rand())
423  {
424  /* Random number between 1 and 6000 */
425  deno = RAND_IN_RANGE(6000ULL);
426  }
427  else
428  {
429  gint64 norm = RAND_IN_RANGE (11ULL);
430 
431  /* multiple of 10, between 1 and 1 million */
432  deno = 1;
433  while (norm)
434  {
435  deno *= 10;
436  norm --;
437  }
438  }
439  }
440  /* Make sure we have a non-zero denominator */
441  if (0 == deno) deno = 1;
442 
443  /* Arbitrary random numbers can cause pointless overflow during
444  * calculations, in particular the revaluing in xaccSplitSetValue where an
445  * input gnc_numeric is converted to use a new denominator. To prevent that,
446  * the numerator is clamped to the larger of num_limit / deno or num_limit /
447  * max_denom_mult.
448  */
449  limit = num_limit / (max_denom_mult / deno == 0 ? max_denom_mult : max_denom_mult / deno);
450  numer = get_random_gint64 ();
451  if (numer > limit)
452  {
453  int64_t num = numer % limit;
454  if (num)
455  numer = num;
456  else
457  numer = limit;
458  }
459  if (0 == numer) numer = 1;
460  g_log("test.engine.suff", G_LOG_LEVEL_INFO, "New GncNumeric %" PRIu64 " / %" PRIu64 " !\n", numer, deno);
461  return gnc_numeric_create(numer, deno);
462 }
463 
464 
465 /* Rate here really means price or exchange rate, this is used solely
466  * to compute an amount from a randomly-created value. */
467 static gnc_numeric
468 get_random_rate (void)
469 {
470  /* Large rates blow up xaccSplitAssignToLot, so we clamp the rate
471  * at a smallish value */
472  gint64 numer = get_random_gint64 () % (2ULL << 24);
473  gint64 denom = 100LL;
474  return gnc_numeric_create (numer, denom);
475 }
476 
477 /* ================================================================= */
478 /* Commodity stuff */
479 
480 const char *types[] =
481 {
482  "NASDAQ",
483  "NYSE",
484  "EUREX",
485  "FUND",
486  "AMEX",
487  NULL
488 };
489 
490 const char*
491 get_random_commodity_namespace(void)
492 {
493  return get_random_string_in_array(types);
494 }
495 
496 static gnc_commodity *
497 get_random_commodity_from_table (gnc_commodity_table *table)
498 {
499  GList *namespaces;
500  gnc_commodity *com = NULL;
501 
502  g_return_val_if_fail (table, NULL);
503 
504  namespaces = gnc_commodity_table_get_namespaces (table);
505 
506  do
507  {
508  GList *commodities;
509  char *name_space;
510 
511  name_space = get_random_list_element (namespaces);
512 
513  commodities = gnc_commodity_table_get_commodities (table, name_space);
514  if (!commodities)
515  continue;
516 
517  com = get_random_list_element (commodities);
518 
519  g_list_free (commodities);
520 
521  }
522  while (!com);
523 
524 
525  g_list_free (namespaces);
526 
527  return com;
528 }
529 
531 get_random_commodity (QofBook *book)
532 {
533  gnc_commodity *ret;
534  gchar *name;
535  const gchar *space;
536  gchar *mn;
537  gchar *cusip;
538  int ran_int;
539  gnc_commodity_table *table;
540 
541  table = gnc_commodity_table_get_table (book);
542 
543 #if 0
544  if (table &&
545  (gnc_commodity_table_get_size (table) > 0) &&
546  get_random_int_in_range (1, 5) < 5)
547  return get_random_commodity_from_table (table);
548 #endif
549 
550  mn = get_random_string_length_in_range(1, 3);
551  space = get_random_commodity_namespace();
552 
553  if (table)
554  {
555  ret = gnc_commodity_table_lookup (table, space, mn);
556 
557  if (ret)
558  {
559  g_free (mn);
560  return ret;
561  }
562  }
563 
564  name = get_random_string();
565  cusip = get_random_string();
566 
567  ran_int = get_random_int_in_range(min_scu, max_scu);
568 
569  ret = gnc_commodity_new(book, name, space, mn, cusip, ran_int);
570 
571  g_free(mn);
572  g_free(name);
573  g_free(cusip);
574 
575  if (table)
576  ret = gnc_commodity_table_insert (table, ret);
577 
578  return ret;
579 }
580 
581 void
582 make_random_changes_to_commodity (gnc_commodity *com)
583 {
584  char *str;
585 
586  g_return_if_fail (com);
587 
588  str = get_random_string ();
589  gnc_commodity_set_namespace (com, str);
590  g_free (str);
591 
592  str = get_random_string ();
593  gnc_commodity_set_mnemonic (com, str);
594  g_free (str);
595 
596  str = get_random_string ();
597  gnc_commodity_set_fullname (com, str);
598  g_free (str);
599 
600  str = get_random_string ();
601  gnc_commodity_set_cusip (com, str);
602  g_free (str);
603 
604  gnc_commodity_set_fraction (com, get_random_int_in_range (1, 100000));
605 }
606 
607 void
608 make_random_changes_to_commodity_table (gnc_commodity_table *table)
609 {
610  GList *namespaces;
611  GList *node;
612 
613  g_return_if_fail (table);
614 
615  namespaces = gnc_commodity_table_get_namespaces (table);
616 
617  for (node = namespaces; node; node = node->next)
618  {
619  const char *ns = node->data;
620  GList *commodities;
621  GList *com_node;
622 
624  continue;
625 
626  commodities = gnc_commodity_table_get_commodities (table, ns);
627 
628  for (com_node = commodities; com_node; com_node = com_node->next)
629  {
630  gnc_commodity *com = com_node->data;
631 
632  gnc_commodity_table_remove (table, com);
633  make_random_changes_to_commodity (com);
634  gnc_commodity_table_insert (table, com);
635  }
636 
637  g_list_free (commodities);
638  }
639 
640  g_list_free (namespaces);
641 }
642 /* ================================================================= */
643 /* Price stuff */
644 
645 void
646 make_random_changes_to_price (QofBook *book, GNCPrice *p)
647 {
648  Timespec *ts;
649  char *string;
650  gnc_commodity *c;
651 
652  g_return_if_fail (book && p);
653 
654  gnc_price_begin_edit (p);
655 
656  c = get_random_commodity (book);
657  gnc_price_set_commodity (p, c);
658 
659  c = get_random_commodity (book);
660  gnc_price_set_currency (p, c);
661 
662  ts = get_random_timespec ();
663  gnc_price_set_time (p, *ts);
664  g_free (ts);
665 
666  string = get_random_string ();
667  gnc_price_set_source (p, string);
668  g_free (string);
669 
670  string = get_random_string ();
671  gnc_price_set_typestr (p, string);
672  g_free (string);
673 
674  gnc_price_set_value (p, get_random_gnc_numeric (GNC_DENOM_AUTO));
675 
676  gnc_price_commit_edit (p);
677 }
678 
679 GNCPrice *
680 get_random_price(QofBook *book)
681 {
682  GNCPrice *p;
683 
684  p = gnc_price_create (book);
685  if (!p)
686  {
687  failure_args("engine-stuff", __FILE__, __LINE__,
688  "get_random_price failed");
689  return NULL;
690  }
691 
692  make_random_changes_to_price (book, p);
693  if (!p)
694  {
695  failure_args("engine-stuff", __FILE__, __LINE__,
696  "make_random_changes_to_price failed");
697  return NULL;
698  }
699 
700  return p;
701 }
702 
703 gboolean
704 make_random_pricedb (QofBook *book, GNCPriceDB *db)
705 {
706  int num_prices;
707  gboolean check;
708 
709  num_prices = get_random_int_in_range (1, 41);
710  if (num_prices < 1) /* should be impossible */
711  {
712  failure_args("engine-stuff", __FILE__, __LINE__,
713  "get_random_int_in_range failed");
714  return FALSE;
715  }
716 
717  while (num_prices-- > 0)
718  {
719  GNCPrice *p;
720 
721  p = get_random_price (book);
722  if (!p)
723  {
724  failure_args("engine-stuff", __FILE__, __LINE__,
725  "get_random_price failed");
726  return FALSE;
727  }
728 
729  check = gnc_pricedb_add_price (db, p);
730  if (!check)
731  {
732  return check;
733  }
734 
735  gnc_price_unref (p);
736  }
737  return TRUE;
738 }
739 
740 GNCPriceDB *
741 get_random_pricedb(QofBook *book)
742 {
743  GNCPriceDB *db;
744 
745  db = gnc_pricedb_get_db (book);
746  if (!db)
747  {
748  failure_args("engine-stuff", __FILE__, __LINE__,
749  "gnc_pricedb_get_db failed");
750  return NULL;
751  }
752  if (!make_random_pricedb (book, db))
753  {
754  return NULL;
755  }
756 
757  return db;
758 }
759 
760 static gboolean
761 price_accumulator (GNCPrice *p, gpointer data)
762 {
763  GList **list = data;
764 
765  *list = g_list_prepend (*list, p);
766 
767  return TRUE;
768 }
769 
770 void
771 make_random_changes_to_pricedb (QofBook *book, GNCPriceDB *pdb)
772 {
773  GList *list = NULL;
774  GList *node;
775 
776  g_return_if_fail (pdb);
777 
778  gnc_pricedb_foreach_price (pdb, price_accumulator, &list, FALSE);
779 
780  for (node = list; node; node = node->next)
781  {
782  GNCPrice *p = node->data;
783 
784  switch (get_random_int_in_range (0, 5))
785  {
786  case 0: /* Delete */
787  gnc_pricedb_remove_price (pdb, p);
788  break;
789 
790  case 1:
791  case 2: /* Change */
792  make_random_changes_to_price (book, p);
793  break;
794 
795  default: /* nothing */
796  break;
797  }
798  }
799 
800  g_list_free (list);
801 
802  /* Add a few new ones */
803  {
804  int i = get_random_int_in_range (1, 5);
805 
806  while (i--)
807  {
808  GNCPrice *p = get_random_price (book);
809 
810  gnc_pricedb_add_price (pdb, p);
811 
812  gnc_price_unref (p);
813  }
814  }
815 }
816 
817 /* ================================================================= */
818 /* Account stuff */
819 
820 static void
821 set_account_random_string(Account* act,
822  void(*func)(Account *act, const gchar*str))
823 {
824  gchar *tmp_str = get_random_string();
825  if (tmp_str)
826  {
827  (func)(act, tmp_str);
828  g_free(tmp_str);
829  }
830 }
831 
832 static void
833 set_account_random_string_from_array(
834  Account* act, void(*func)(Account *act, const gchar*str),
835  const gchar *list[])
836 {
837  const gchar *tmp_str = get_random_string_in_array(list);
838  if (tmp_str)
839  (func)(act, tmp_str);
840 
841 }
842 
843 static void
844 account_add_subaccounts (QofBook *book, Account *account, int depth)
845 {
846  int num_accounts;
847 
848  if (depth == 0)
849  return;
850 
851  num_accounts = get_random_int_in_range (1, 10);
852  while (num_accounts-- > 0)
853  {
854  Account *sub = get_random_account (book);
855 
856  gnc_account_append_child (account, sub);
857 
858  total_num_accounts ++;
859  if (total_num_accounts > max_total_accounts) return;
860 
861  account_add_subaccounts (book, sub, depth - 1);
862  }
863 }
864 
865 static void
866 make_random_account_tree (QofBook *book, Account *root)
867 {
868  int depth;
869 
870  g_return_if_fail (book);
871  g_return_if_fail (root);
872 
873  total_num_accounts = 0;
874  depth = get_random_int_in_range (1, max_tree_depth);
875 
876  account_add_subaccounts (book, root, depth);
877 
878  /* Make sure we have at least two accounts! */
879  if (total_num_accounts <= 1)
880  account_add_subaccounts (book, root, 1);
881 }
882 
883 Account *
884 get_random_account_tree (QofBook *book)
885 {
886  Account * root;
887 
888  g_return_val_if_fail (book, NULL);
889 
890  root = gnc_book_get_root_account (book);
891  if (!root)
892  {
893  root = xaccMallocAccount (book);
894  gnc_book_set_root_account (book, root);
895  }
896 
897  make_random_account_tree (book, root);
898 
899  return root;
900 }
901 
902 /* ================================================================= */
903 /* transaction stuff */
904 
910 static void
911 add_random_splits(QofBook *book, Transaction *trn, GList *account_list)
912 {
913  Account *acc, *bcc;
914  Split *s1, *s2;
915  gnc_numeric val;
916  int s2_scu;
917 
918  /* Gotta have at least two different accounts */
919  if (1 >= g_list_length (account_list)) return;
920 
921  acc = get_random_list_element (account_list);
922  xaccTransBeginEdit(trn);
923  s1 = get_random_split(book, acc, trn);
924 
925  bcc = get_random_list_element (account_list);
926  if ((bcc == acc) && (!do_bork()))
927  {
928  /* Make sure that each side of the transaction is in
929  * a different account; otherwise get weirdness in lot
930  * calculcations. ... Hmm maybe should fix lots in
931  * this case? */
932  while (bcc == acc)
933  {
934  bcc = get_random_list_element (account_list);
935  }
936  }
937 
938  /* Set up two splits whose values really are opposites. */
939  val = xaccSplitGetValue(s1);
940  s2 = get_random_split(book, bcc, trn);
942 
943  /* Other split should have equal and opposite value */
944  if (do_bork())
945  {
946  val = get_random_gnc_numeric(GNC_DENOM_AUTO);
947  g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG, "Borking second %" PRIu64
948  " / %" PRIu64 ", scu %d\n", val.num, val.denom, s2_scu);
949  }
950  val = gnc_numeric_neg(val);
951  xaccSplitSetValue(s2, val);
952  if (val.denom != s2_scu)
953  {
954  if (val.denom > s2_scu)
955  val.num /= val.denom / s2_scu;
956  val.denom = s2_scu;
957  }
958  xaccSplitSetAmount(s2, val);
959  xaccTransCommitEdit(trn);
960 }
961 
962 typedef struct
963 {
964  GncGUID guid;
965 } TransInfo;
966 
967 void
968 make_random_changes_to_transaction_and_splits (QofBook *book,
969  Transaction *trans,
970  GList *accounts)
971 {
972  GList *splits;
973  GList *node;
974  Split *split;
975 
976  g_return_if_fail (book);
977  g_return_if_fail (trans);
978  g_return_if_fail (accounts);
979 
980  xaccTransBeginEdit (trans);
981 
982  make_random_changes_to_transaction (book, trans);
983 
984  switch (get_random_int_in_range (0, 3))
985  {
986  case 0: /* delete some splits, add some more */
987  if (xaccTransGetVoidStatus (trans))
988  break;
989 
990  do
991  {
992  split = xaccTransGetSplit (trans, 0);
993 
994  xaccSplitDestroy (split);
995  }
996  while (split);
997 
998  add_random_splits (book, trans, accounts);
999 
1000  /* fall through */
1001 
1002  case 1: /* move the splits around */
1003  if (xaccTransGetVoidStatus (trans))
1004  break;
1005 
1006  splits = xaccTransGetSplitList (trans);
1007  for (node = splits; node; node = node->next)
1008  {
1009  Split *split = node->data;
1010  Account *account;
1011 
1012  account = get_random_list_element (accounts);
1013 
1014  xaccAccountInsertSplit (account, split);
1015  }
1016  break;
1017 
1018  case 2: /* destroy the transaction */
1019  xaccTransDestroy (trans);
1020  xaccTransCommitEdit (trans);
1021  return;
1022 
1023  default: /* do nothing */
1024  break;
1025  }
1026 
1027  if (xaccTransGetVoidStatus (trans))
1028  {
1029  xaccTransCommitEdit (trans);
1030  return;
1031  }
1032 
1033  /* mess with the splits */
1034  splits = xaccTransGetSplitList (trans);
1035  for (node = splits; node; node = node->next)
1036  {
1037  Split *split = node->data;
1038 
1039  if (get_random_boolean ())
1040  make_random_changes_to_split (split);
1041  }
1042 
1043  if (get_random_boolean ())
1044  xaccTransCommitEdit (trans);
1045  else
1046  xaccTransRollbackEdit (trans);
1047 }
1048 
1049 static int
1050 add_trans_helper (Transaction *trans, gpointer data)
1051 {
1052  TransInfo *ti;
1053  GList **list = data;
1054 
1055  ti = g_new (TransInfo, 1);
1056 
1057  ti->guid = *xaccTransGetGUID (trans);
1058 
1059  *list = g_list_prepend (*list, ti);
1060  return 0;
1061 }
1062 
1063 void
1064 make_random_changes_to_level (QofBook *book, Account *parent)
1065 {
1066  Account *new_account;
1067  Account *account;
1068  GList *accounts;
1069  GList *transes;
1070  GList *splits;
1071  GList *node;
1072 
1073  g_return_if_fail (parent && book);
1074 
1075  accounts = gnc_account_get_descendants (parent);
1076 
1077  /* Add a new account */
1078  new_account = get_random_account (book);
1079 
1080  if (get_random_boolean () || !accounts)
1081  gnc_account_append_child (parent, new_account);
1082  else
1083  {
1084  account = get_random_list_element (accounts);
1085 
1086  gnc_account_append_child (account, new_account);
1087  }
1088 
1089  g_list_free (accounts);
1090  accounts = gnc_account_get_descendants (parent);
1091 
1092  /* Add some new transactions */
1093  add_random_transactions_to_book (book, get_random_int_in_range (1, 6));
1094 
1095  /* Mess with the accounts */
1096  for (node = accounts; node; node = node->next)
1097  {
1098  Account *account = node->data;
1099 
1100  if (get_random_boolean ())
1101  make_random_changes_to_account (book, account);
1102  }
1103 
1104  /* Mess with the transactions & splits */
1105  transes = NULL;
1106  xaccAccountTreeForEachTransaction (parent, add_trans_helper, &transes);
1107 
1108  for (node = transes; node; node = node->next)
1109  {
1110  TransInfo *ti = node->data;
1111  Transaction *trans = xaccTransLookup (&ti->guid, book);
1112 
1113  if (!trans)
1114  continue;
1115 
1116  make_random_changes_to_transaction_and_splits (book, trans, accounts);
1117  }
1118 
1119  for (node = transes; node; node = node->next)
1120  {
1121  TransInfo *ti = node->data;
1122 
1123  g_free (ti);
1124  }
1125  g_list_free (transes);
1126  transes = NULL;
1127 
1128  /* delete an account */
1129  account = get_random_list_element (accounts);
1130 
1131  splits = xaccAccountGetSplitList (account);
1132  splits = g_list_copy (splits);
1133 
1134  for (node = splits; node; node = node->next)
1135  {
1136  Split *split = node->data;
1137 
1138  do
1139  {
1140  new_account = get_random_list_element (accounts);
1141  }
1142  while (new_account == account);
1143 
1144  xaccAccountInsertSplit (new_account, split);
1145  }
1146 
1147  xaccAccountBeginEdit (account);
1148  xaccAccountDestroy (account);
1149 
1150  g_list_free (splits);
1151  g_list_free (accounts);
1152 
1153  accounts = gnc_account_get_descendants (parent);
1154 
1155  /* move some accounts around */
1156  if (accounts && (g_list_length (accounts) > 1))
1157  {
1158  int i = get_random_int_in_range (1, 4);
1159 
1160  while (i--)
1161  {
1162  Account *a1, *a2;
1163 
1164  a1 = get_random_list_element (accounts);
1165 
1166  if (get_random_boolean ())
1167  a2 = get_random_list_element (accounts);
1168  else
1169  a2 = NULL;
1170 
1171  if (!a2)
1172  {
1173  gnc_account_append_child (parent, a1);
1174  continue;
1175  }
1176 
1177  if (a1 == a2 ||
1178  xaccAccountHasAncestor (a1, a2) ||
1179  xaccAccountHasAncestor (a2, a1))
1180  {
1181  i++;
1182  continue;
1183  }
1184 
1185  gnc_account_append_child (a2, a1);
1186  }
1187  }
1188 
1189  g_list_free (accounts);
1190 }
1191 
1192 Account*
1193 get_random_account(QofBook *book)
1194 {
1195  Account *root, *ret;
1196  int tmp_int;
1197 
1198  ret = xaccMallocAccount(book);
1199 
1200  xaccAccountBeginEdit(ret);
1201 
1202  set_account_random_string_from_array(ret, xaccAccountSetName,
1203  sane_account_names);
1204 
1205  tmp_int = get_random_int_in_range(ACCT_TYPE_BANK, NUM_ACCOUNT_TYPES - 1);
1206  xaccAccountSetType(ret, tmp_int);
1207 
1208  set_account_random_string(ret, xaccAccountSetCode);
1209  set_account_random_string(ret, xaccAccountSetDescription);
1210 
1211  xaccAccountSetCommodity(ret, get_random_commodity(book));
1212 
1213  qof_instance_set_slots(QOF_INSTANCE(ret), get_random_kvp_frame());
1214 
1215  root = gnc_book_get_root_account (book);
1216  if (!root)
1217  {
1218  root = xaccMallocAccount (book);
1219  gnc_book_set_root_account (book, root);
1220  }
1221  gnc_account_append_child (root, ret);
1222  xaccAccountCommitEdit(ret);
1223 
1224  return ret;
1225 }
1226 
1227 void
1228 make_random_changes_to_account (QofBook *book, Account *account)
1229 {
1230  int tmp_int;
1231 
1232  g_return_if_fail (account);
1233 
1234  xaccAccountBeginEdit (account);
1235 
1236  set_account_random_string (account, xaccAccountSetName);
1237 
1238  tmp_int = get_random_int_in_range (ACCT_TYPE_BANK, NUM_ACCOUNT_TYPES - 1);
1239  xaccAccountSetType (account, tmp_int);
1240 
1241  set_account_random_string (account, xaccAccountSetCode);
1242  set_account_random_string (account, xaccAccountSetDescription);
1243 
1244  xaccAccountSetCommodity (account, get_random_commodity(book));
1245 
1246  qof_instance_set_slots(QOF_INSTANCE(account), get_random_kvp_frame());
1247 
1248  xaccAccountCommitEdit (account);
1249 }
1250 
1251 static void
1252 set_split_random_string(Split *spl,
1253  void(*func)(Split *act, const gchar*str))
1254 {
1255  gchar *tmp_str = get_random_string();
1256  if (tmp_str)
1257  {
1258  (func)(spl, tmp_str);
1259  g_free(tmp_str);
1260  }
1261 }
1262 
1263 /* Don't do voiding here, it should be done by xaccTransVoid */
1264 static char possible_chars[] = { NREC, CREC, YREC, FREC };
1265 
1266 Split*
1267 get_random_split(QofBook *book, Account *acct, Transaction *trn)
1268 {
1269  Split *ret;
1270  gnc_numeric amt = {0, 1}, val = {0, 1}, rate = {0, 0};
1271  const gchar *str;
1272  gnc_commodity *com;
1273  int scu, denom;
1274  Timespec *ts;
1275 
1276  com = xaccTransGetCurrency (trn);
1277  scu = gnc_commodity_get_fraction(com);
1278 
1279  ret = xaccMallocSplit(book);
1280 
1281  str = get_random_string_in_array(sane_descriptions);
1282  xaccSplitSetMemo(ret, str);
1283  str = get_random_string_in_array(sane_actions);
1284  xaccSplitSetAction(ret, str);
1285 
1286  xaccSplitSetReconcile(ret, possible_chars[get_random_int_in_range(0, 3)]);
1287 
1288  ts = get_random_timespec();
1290  g_free(ts);
1291 
1292  /* Split must be in an account before we can set an amount */
1293  /* and in a transaction before it can be added to an account. */
1294  xaccTransBeginEdit(trn);
1295  xaccSplitSetParent(ret, trn);
1296  xaccSplitSetAccount(ret, acct);
1297 
1298  do
1299  {
1300  val = get_random_gnc_numeric (scu);
1301  if (val.num == 0)
1302  fprintf(stderr, "get_random_split: Created split with zero value: %p\n", ret);
1303 
1304  if (!do_bork())
1305 /* Another overflow-prevention measure. A numerator near the overflow limit can
1306  * be made too large by replacing the denominator with a smaller scu.
1307  */
1308  {
1309  if (val.denom > scu && val.num > num_limit / (max_denom_mult / scu))
1310  {
1311  int64_t new_num = val.num / (val.denom / scu);
1312  g_log("test.engine.suff", G_LOG_LEVEL_DEBUG,
1313  "Adjusting val.denom from %" PRIu64 " to %" PRIu64 "\n",
1314  val.num, new_num);
1315  val.num = new_num;
1316  }
1317  val.denom = scu;
1318  }
1319  }
1320  while (gnc_numeric_check(val) != GNC_ERROR_OK);
1321  g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG,
1322  "Random split value: %" PRIu64 " / %" PRIu64 ", scu %d\n",
1323  val.num, val.denom, scu);
1324  xaccSplitSetValue(ret, val);
1325 
1326  /* If the currencies are the same, the split amount should equal
1327  * the split value (unless we bork it on purpose) */
1329  xaccSplitGetAccount(ret)));
1331  xaccAccountGetCommodity(acct)) &&
1332  (!do_bork()))
1333  {
1334  amt = val;
1335  }
1336  else
1337  {
1338  do
1339  {
1340  rate = get_random_rate ();
1341  amt = gnc_numeric_div(val, rate, denom, GNC_HOW_RND_ROUND_HALF_UP);
1342  }
1343  while (gnc_numeric_check(amt) != GNC_ERROR_OK);
1344  }
1345  g_log ("test.engine.suff", G_LOG_LEVEL_DEBUG, "Random split amount: %"
1346  PRIu64 " / %" PRIu64 ", rate %" PRIu64 " / %" PRIu64 "\n",
1347  amt.num, amt.denom, rate.num, rate.denom);
1348 
1349 
1350  xaccSplitSetAmount(ret, amt);
1351 
1352  /* Make sure val and amt have the same sign. Note that amt is
1353  also allowed to be zero, because that is caused by a small
1354  rate. */
1355  if (gnc_numeric_positive_p(val))
1356  g_assert(!gnc_numeric_negative_p(amt)); /* non-negative amt */
1357  else
1358  g_assert(!gnc_numeric_positive_p(amt)); /* non-positive amt */
1359 
1360 // g_assert(amt.num < (2LL << 56));
1361  qof_instance_set_slots(QOF_INSTANCE (ret), get_random_kvp_frame());
1362  xaccTransCommitEdit(trn);
1363 
1364  return ret;
1365 }
1366 
1367 void
1368 make_random_changes_to_split (Split *split)
1369 {
1370  Transaction *trans;
1371  Timespec *ts;
1372 
1373  g_return_if_fail (split);
1374 
1375  trans = xaccSplitGetParent (split);
1376 
1377  xaccTransBeginEdit (trans);
1378 
1379  set_split_random_string (split, xaccSplitSetMemo);
1380  set_split_random_string (split, xaccSplitSetAction);
1381 
1382  xaccSplitSetReconcile (split, possible_chars[get_random_int_in_range(0, 3)]);
1383 
1384  ts = get_random_timespec();
1385  xaccSplitSetDateReconciledTS (split, ts);
1386  g_free(ts);
1387 
1388  qof_instance_set_slots (QOF_INSTANCE (split), get_random_kvp_frame());
1389 
1390  /* Don't change share values/prices here, since that would
1391  * throw transactions out of balance. Do that in the corresponding
1392  * change transaction function. */
1393 
1394  xaccTransCommitEdit (trans);
1395 }
1396 
1397 static void
1398 set_tran_random_string(Transaction* trn,
1399  void(*func)(Transaction *act, const gchar*str))
1400 {
1401  gchar *tmp_str = get_random_string();
1402  if (!trn || !(&trn->inst))
1403  {
1404  return;
1405  }
1406  if (tmp_str)
1407  {
1408  xaccTransBeginEdit(trn);
1409  (func)(trn, tmp_str);
1410  g_free(tmp_str);
1411  xaccTransCommitEdit(trn);
1412  }
1413 }
1414 
1415 static void
1416 set_tran_random_string_from_array(
1417  Transaction* trn, void(*func)(Transaction *trn, const gchar*str),
1418  const gchar *list[])
1419 {
1420  const gchar *tmp_str = get_random_string_in_array(list);
1421  if (tmp_str)
1422  (func)(trn, tmp_str);
1423 }
1424 
1425 
1426 static void
1427 trn_add_ran_timespec(Transaction *trn, void (*func)(Transaction*,
1428  const Timespec*))
1429 {
1430  Timespec *to_set;
1431 
1432  to_set = get_random_timespec();
1433  func(trn, to_set);
1434  g_free(to_set);
1435 }
1436 
1437 
1438 Transaction *
1439 get_random_transaction_with_currency(QofBook *book,
1440  gnc_commodity *currency,
1441  GList *account_list)
1442 {
1443  Transaction* trans;
1444  KvpFrame *f;
1445  gint num;
1446  gchar *numstr;
1447 
1448  if (!account_list)
1449  {
1450  account_list = gnc_account_get_descendants (gnc_book_get_root_account (book));
1451  }
1452 
1453  /* Gotta have at least two different accounts */
1454  if (1 >= g_list_length (account_list))
1455  {
1456  failure_args("engine-stuff", __FILE__, __LINE__,
1457  "get_random_transaction_with_currency: account_list too short");
1458  return NULL;
1459  }
1460 
1461  numstr = g_new0(gchar, 10);
1462 
1463  trans = xaccMallocTransaction(book);
1464 
1465  xaccTransBeginEdit(trans);
1466 
1467  xaccTransSetCurrency (trans,
1468  currency ? currency :
1469  get_random_commodity (book));
1470 
1471  num = get_random_int_in_range (1, max_trans_num);
1472  g_snprintf(numstr, 10, "%d", num);
1473  xaccTransSetNum(trans, numstr);
1474  set_tran_random_string_from_array(trans, xaccTransSetDescription,
1475  sane_descriptions);
1476  trn_add_ran_timespec(trans, xaccTransSetDatePostedTS);
1477  trn_add_ran_timespec(trans, xaccTransSetDateEnteredTS);
1478 
1479  f = get_random_kvp_frame();
1480  xaccTransSetSlots_nc(trans, f);
1481 
1482  add_random_splits(book, trans, account_list);
1483 
1484  if (get_random_int_in_range (1, 10) == 1)
1485  {
1486  char *reason = get_random_string ();
1487  xaccTransVoid (trans, reason);
1488  g_free (reason);
1489  }
1490 
1491  xaccTransCommitEdit(trans);
1492  if (!trans)
1493  {
1494  failure_args("engine-stuff", __FILE__, __LINE__,
1495  "get_random_transaction_with_currency failed");
1496  return NULL;
1497  }
1498 
1499  return trans;
1500 }
1501 
1502 Transaction*
1503 get_random_transaction (QofBook *book)
1504 {
1505  Transaction *ret;
1506 
1507  g_return_val_if_fail(book, NULL);
1508  ret = get_random_transaction_with_currency (book, NULL, NULL);
1509  if (!ret)
1510  {
1511  failure_args("engine-stuff", __FILE__, __LINE__,
1512  "get_random_transaction failed");
1513  return NULL;
1514  }
1515  return ret;
1516 }
1517 
1518 void
1519 make_random_changes_to_transaction (QofBook *book, Transaction *trans)
1520 {
1521  g_return_if_fail (trans && book);
1522 
1523  if (xaccTransGetVoidStatus (trans))
1524  {
1525  if (get_random_int_in_range (1, 2) == 1)
1526  xaccTransUnvoid (trans);
1527  return;
1528  }
1529 
1530  xaccTransBeginEdit (trans);
1531 
1532  xaccTransSetCurrency (trans, get_random_commodity (book));
1533 
1534  set_tran_random_string (trans, xaccTransSetNum);
1535 
1536  trn_add_ran_timespec (trans, xaccTransSetDatePostedTS);
1537  trn_add_ran_timespec (trans, xaccTransSetDateEnteredTS);
1538 
1539  set_tran_random_string (trans, xaccTransSetDescription);
1540 
1541  xaccTransSetSlots_nc (trans, get_random_kvp_frame());
1542 
1543  /* Do split manipulations in higher-level functions */
1544 
1545  xaccTransCommitEdit (trans);
1546 }
1547 
1548 
1549 static GList *
1550 get_random_guids(int max)
1551 {
1552  GList *guids = NULL;
1553  int num_guids;
1554 
1555  if (max < 1) return NULL;
1556 
1557  num_guids = get_random_int_in_range (1, max);
1558 
1559  while (num_guids-- > 0)
1560  guids = g_list_prepend (guids, get_random_guid ());
1561 
1562  return guids;
1563 }
1564 
1565 static void
1566 free_random_guids(GList *guids)
1567 {
1568  GList *node;
1569 
1570  for (node = guids; node; node = node->next)
1571  g_free (node->data);
1572 
1573  g_list_free (guids);
1574 }
1575 
1576 static QofQueryOp
1577 get_random_queryop(void)
1578 {
1579  int op_num = get_random_int_in_range(1, 11);
1580  QofQueryOp op = QOF_QUERY_AND;
1581  /* = get_random_int_in_range (1, QOF_QUERY_XOR); */
1582 
1583  /* Let's make it MUCH more likely to get AND and OR */
1584  switch (op_num)
1585  {
1586  case 1:
1587  case 2:
1588  case 3:
1589  case 4:
1590  op = QOF_QUERY_AND;
1591  break;
1592  case 5:
1593  case 6:
1594  case 7:
1595  case 8:
1596  op = QOF_QUERY_OR;
1597  break;
1598  case 9:
1599  op = QOF_QUERY_NAND;
1600  break;
1601  case 10:
1602  op = QOF_QUERY_NOR;
1603  break;
1604  case 11:
1605  op = QOF_QUERY_XOR;
1606  break;
1607  default:
1608  g_assert_not_reached();
1609  break;
1610  };
1611  if (gnc_engine_debug_random) printf ("op = %d (int was %d), ", op, op_num);
1612  return op;
1613 }
1614 
1615 static GSList *
1616 get_random_kvp_path (void)
1617 {
1618  GSList *path;
1619  gint len;
1620 
1621  path = NULL;
1622  len = get_random_int_in_range (1, kvp_max_depth);
1623 
1624  while (len--)
1625  path = g_slist_prepend (path, get_random_string_without ("\n\\"));
1626 
1627  return g_slist_reverse (path);
1628 }
1629 
1630 static void
1631 free_random_kvp_path (GSList *path)
1632 {
1633  GSList *node;
1634 
1635  for (node = path; node; node = node->next)
1636  g_free (node->data);
1637 
1638  g_slist_free (path);
1639 }
1640 
1641 static QofIdType
1642 get_random_id_type (void)
1643 {
1644  switch (get_random_int_in_range (1, 3))
1645  {
1646  case 1:
1647  return GNC_ID_SPLIT;
1648  case 2:
1649  return GNC_ID_TRANS;
1650  case 3:
1651  return GNC_ID_ACCOUNT;
1652  default:
1653  return get_random_string ();
1654  }
1655 }
1656 
1657 typedef enum
1658 {
1659  BY_STANDARD = 1,
1660  BY_DATE,
1661  BY_DATE_ENTERED,
1662  BY_DATE_RECONCILED,
1663  BY_NUM,
1664  BY_AMOUNT,
1665  BY_MEMO,
1666  BY_DESC,
1667  BY_NONE
1668 } sort_type_t;
1669 
1670 static void
1671 set_query_sort (QofQuery *q, sort_type_t sort_code)
1672 {
1673  GSList *p1 = NULL, *p2 = NULL, *p3 = NULL, *standard;
1674 
1675  standard = g_slist_prepend (NULL, QUERY_DEFAULT_SORT);
1676 
1677  switch (sort_code)
1678  {
1679  case BY_STANDARD:
1680  p1 = standard;
1681  break;
1682  case BY_DATE:
1683  p1 = g_slist_prepend (p1, TRANS_DATE_POSTED);
1684  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1685  p2 = standard;
1686  break;
1687  case BY_DATE_ENTERED:
1688  p1 = g_slist_prepend (p1, TRANS_DATE_ENTERED);
1689  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1690  p2 = standard;
1691  break;
1692  case BY_DATE_RECONCILED:
1693  p1 = g_slist_prepend (p1, SPLIT_RECONCILE);
1694  p2 = g_slist_prepend (p2, SPLIT_DATE_RECONCILED);
1695  p3 = standard;
1696  break;
1697  case BY_NUM:
1698  p1 = g_slist_prepend (p1, TRANS_NUM);
1699  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1700  p2 = standard;
1701  break;
1702  case BY_AMOUNT:
1703  p1 = g_slist_prepend (p1, SPLIT_VALUE);
1704  p2 = standard;
1705  break;
1706  case BY_MEMO:
1707  p1 = g_slist_prepend (p1, SPLIT_MEMO);
1708  p2 = standard;
1709  break;
1710  case BY_DESC:
1711  p1 = g_slist_prepend (p1, TRANS_DESCRIPTION);
1712  p1 = g_slist_prepend (p1, SPLIT_TRANS);
1713  p2 = standard;
1714  break;
1715  case BY_NONE:
1716  g_slist_free (standard);
1717  break;
1718  default:
1719  g_slist_free (standard);
1720  g_return_if_fail (FALSE);
1721  break;
1722  }
1723 
1724  qof_query_set_sort_order (q, p1, p2, p3);
1725 }
1726 
1727 QofQuery *
1728 get_random_query(void)
1729 {
1730  QofQuery *q;
1731  int num_terms;
1732 
1733  num_terms = get_random_int_in_range (1, 3);
1734  if (gnc_engine_debug_random) printf("num_terms = %d", num_terms);
1735 
1736  q = qof_query_create_for(GNC_ID_SPLIT);
1737 
1738  while (num_terms-- > 0)
1739  {
1740  gint pr_type;
1741  KvpValue *value;
1742  Timespec *start;
1743  Timespec *end;
1744  GList *guids;
1745  GSList *path;
1746  char *string;
1747  GncGUID *guid;
1748 
1749  pr_type = get_random_int_in_range (1, 20);
1750  if (gnc_engine_debug_random) printf("\n pr_type = %d ", pr_type);
1751 
1752  switch (pr_type)
1753  {
1754  case 1: /*PR_ACCOUNT */
1755  guids = get_random_guids (10);
1756  xaccQueryAddAccountGUIDMatch
1757  (q,
1758  guids,
1759  get_random_int_in_range (1, QOF_GUID_MATCH_NONE),
1760  get_random_queryop ());
1761  free_random_guids (guids);
1762  break;
1763 
1764  case 2: /*PR_ACTION */
1765  string = get_random_string_without ("\\");
1766  xaccQueryAddActionMatch (q,
1767  string,
1768  get_random_boolean (),
1769  get_random_boolean (),
1770  get_random_int_in_range (1, QOF_COMPARE_CONTAINS),
1771  get_random_queryop ());
1772  g_free (string);
1773  break;
1774 
1775  case 3: /* PR_BALANCE */
1776  xaccQueryAddBalanceMatch
1777  (q,
1778  get_random_boolean (),
1779  get_random_queryop ());
1780  break;
1781 
1782  case 4: /* PR_CLEARED */
1783  xaccQueryAddClearedMatch
1784  (q,
1785  get_random_int_in_range (1,
1786  CLEARED_NO |
1787  CLEARED_CLEARED |
1788  CLEARED_RECONCILED |
1789  CLEARED_FROZEN |
1790  CLEARED_VOIDED),
1791  get_random_queryop ());
1792  break;
1793 
1794  case 5: /* PR_DATE */
1795  start = get_random_timespec ();
1796  end = get_random_timespec ();
1797  xaccQueryAddDateMatchTS (q,
1798  get_random_boolean (),
1799  *start,
1800  get_random_boolean (),
1801  *end,
1802  get_random_queryop ());
1803  g_free (start);
1804  g_free (end);
1805  break;
1806 
1807  case 6: /* PR_DESC */
1808  string = get_random_string_without ("\\");
1809  xaccQueryAddDescriptionMatch (q,
1810  string,
1811  get_random_boolean (),
1812  get_random_boolean (),
1813  get_random_int_in_range (1, QOF_COMPARE_CONTAINS),
1814  get_random_queryop ());
1815  g_free (string);
1816  break;
1817 
1818  case 7: /* PR_GUID */
1819  guid = get_random_guid ();
1820  xaccQueryAddGUIDMatch (q,
1821  guid,
1822  get_random_id_type (),
1823  get_random_queryop ());
1824  g_free (guid);
1825  break;
1826 
1827  case 8: /* PR_KVP */
1828  path = get_random_kvp_path ();
1829  do
1830  {
1831  value = get_random_kvp_value_depth (-2, kvp_max_depth);
1832  }
1833  while (!value);
1834  xaccQueryAddKVPMatch (q,
1835  path,
1836  value,
1837  get_random_int_in_range (1, QOF_COMPARE_NEQ),
1838  get_random_id_type (),
1839  get_random_queryop ());
1840  kvp_value_delete (value);
1841  free_random_kvp_path (path);
1842  break;
1843 
1844  case 9: /* PR_MEMO */
1845  string = get_random_string_without ("\\");
1846  xaccQueryAddMemoMatch (q,
1847  string,
1848  get_random_boolean (),
1849  get_random_boolean (),
1850  get_random_int_in_range (1, QOF_COMPARE_CONTAINS),
1851  get_random_queryop ());
1852  g_free (string);
1853  break;
1854 
1855  case 10: /* PR_NUM */
1856  string = get_random_string_without ("\\");
1857  xaccQueryAddNumberMatch (q,
1858  string,
1859  get_random_boolean (),
1860  get_random_boolean (),
1861  get_random_int_in_range (1, QOF_COMPARE_CONTAINS),
1862  get_random_queryop ());
1863  g_free (string);
1864  break;
1865 
1866  case 11: /* PR_PRICE */
1867  xaccQueryAddSharePriceMatch
1868  (q,
1869  get_random_gnc_numeric (GNC_DENOM_AUTO),
1870  get_random_int_in_range (1, QOF_COMPARE_NEQ),
1871  get_random_queryop ());
1872  break;
1873 
1874  case 12: /* PR_SHRS */
1875  xaccQueryAddSharesMatch
1876  (q,
1877  get_random_gnc_numeric (GNC_DENOM_AUTO),
1878  get_random_int_in_range (1, QOF_COMPARE_NEQ),
1879  get_random_queryop ());
1880  break;
1881 
1882  case 13: /* PR_VALUE */
1883  xaccQueryAddValueMatch
1884  (q,
1885  get_random_gnc_numeric (GNC_DENOM_AUTO),
1886  get_random_int_in_range (1, QOF_NUMERIC_MATCH_ANY),
1887  get_random_int_in_range (1, QOF_COMPARE_NEQ),
1888  get_random_queryop ());
1889  break;
1890 
1891  default:
1892  if (gnc_engine_debug_random) printf("ignored..");
1893  num_terms++;
1894  break;
1895  }
1896  }
1897 
1898  if (gnc_engine_debug_random) printf ("\n");
1899  set_query_sort (q, get_random_int_in_range (1, BY_NONE));
1900 
1902  get_random_boolean (),
1903  get_random_boolean (),
1904  get_random_boolean ());
1905 
1906  qof_query_set_max_results (q, get_random_int_in_range (-50000, 50000));
1907 
1908  return q;
1909 }
1910 
1911 QofBook *
1912 get_random_book (void)
1913 {
1914  QofBook *book;
1915 
1916  book = qof_book_new ();
1917 
1918  get_random_account_tree (book);
1919  get_random_pricedb (book);
1920 
1921  return book;
1922 }
1923 
1924 QofSession *
1925 get_random_session (void)
1926 {
1927  QofSession *session;
1928  QofBook *book;
1929 
1930  session = qof_session_new ();
1931 
1932  book = qof_session_get_book (session);
1933 
1934  get_random_account_tree (book);
1935  get_random_pricedb (book);
1936 
1937  return session;
1938 }
1939 
1940 void
1941 add_random_transactions_to_book (QofBook *book, gint num_transactions)
1942 {
1943  gnc_commodity_table *table;
1944  GList *accounts;
1945 
1946  if (num_transactions <= 0) return;
1947 
1948  g_return_if_fail (book);
1949 
1950  accounts = gnc_account_get_descendants (gnc_book_get_root_account (book));
1951  g_return_if_fail (accounts);
1952 
1953  table = gnc_commodity_table_get_table (book);
1954 
1955  while (num_transactions--)
1956  {
1957  gnc_commodity *com;
1958 
1959  com = get_random_commodity_from_table (table);
1960  get_random_transaction_with_currency (book, com, accounts);
1961  }
1962  g_list_free (accounts);
1963 }
1964 
1965 void
1966 make_random_changes_to_book (QofBook *book)
1967 {
1968  g_return_if_fail (book);
1969 
1970  make_random_changes_to_level (book, gnc_book_get_root_account (book));
1971  make_random_changes_to_pricedb (book, gnc_pricedb_get_db (book));
1972 
1973 #if 0
1974  make_random_changes_to_commodity_table (gnc_commodity_table_get_table (book));
1975 #endif
1976 }
1977 
1978 void
1979 make_random_changes_to_session (QofSession *session)
1980 {
1981  g_return_if_fail (session);
1982 
1983  make_random_changes_to_book (qof_session_get_book (session));
1984 }
1985 
1986 typedef struct
1987 {
1988  QofIdType where;
1989  GSList *path;
1990  QofQuery *q;
1991 } KVPQueryData;
1992 
1993 static void
1994 add_kvp_value_query (const char *key, KvpValue *value, gpointer data)
1995 {
1996  KVPQueryData *kqd = data;
1997  GSList *node;
1998 
1999  kqd->path = g_slist_append (kqd->path, (gpointer) key);
2000 
2001  if (kvp_value_get_type (value) == KVP_TYPE_FRAME)
2003  add_kvp_value_query, data);
2004  else
2005  xaccQueryAddKVPMatch (kqd->q, kqd->path, value,
2006  QOF_COMPARE_EQUAL, kqd->where,
2007  QOF_QUERY_AND);
2008 
2009  node = g_slist_last (kqd->path);
2010  kqd->path = g_slist_remove_link (kqd->path, node);
2011  g_slist_free_1 (node);
2012 }
2013 
2014 static void
2015 add_kvp_query (QofQuery *q, KvpFrame *frame, QofIdType where)
2016 {
2017  KVPQueryData kqd;
2018 
2019  kqd.where = where;
2020  kqd.path = NULL;
2021  kqd.q = q;
2022 
2023  kvp_frame_for_each_slot (frame, add_kvp_value_query, &kqd);
2024 }
2025 
2026 static gboolean include_price = TRUE;
2027 
2028 void
2029 trans_query_include_price (gboolean include_price_in)
2030 {
2031  include_price = include_price_in;
2032 }
2033 
2034 TestQueryTypes
2035 get_random_query_type (void)
2036 {
2037  switch (get_random_int_in_range (0, 4))
2038  {
2039  case 0:
2040  return SIMPLE_QT;
2041  case 1:
2042  return SPLIT_KVP_QT;
2043  case 2:
2044  return TRANS_KVP_QT;
2045  case 3:
2046  return ACCOUNT_KVP_QT;
2047  case 4:
2048  return GUID_QT;
2049  default:
2050  return SIMPLE_QT;
2051  }
2052 }
2053 
2054 QofQuery *
2055 make_trans_query (Transaction *trans, TestQueryTypes query_types)
2056 {
2057  Account *a;
2058  gnc_numeric n;
2059  QofQuery *q;
2060  Split *s;
2061 
2062  if (query_types == RANDOM_QT)
2063  query_types = get_random_query_type ();
2064 
2065  q = qof_query_create_for(GNC_ID_SPLIT);
2066 
2067  s = xaccTransGetSplit (trans, 0);
2068  a = xaccSplitGetAccount (s);
2069 
2070  if (query_types & SIMPLE_QT)
2071  {
2072  xaccQueryAddSingleAccountMatch (q, xaccSplitGetAccount (s), QOF_QUERY_AND);
2073 
2074  if (xaccTransGetDescription(trans) && *xaccTransGetDescription(trans) != '\0')
2075  {
2076  xaccQueryAddDescriptionMatch (q, xaccTransGetDescription (trans),
2077  TRUE, FALSE, QOF_COMPARE_CONTAINS, QOF_QUERY_AND);
2078  }
2079 
2080  if (xaccTransGetNum(trans) && *xaccTransGetNum(trans) != '\0')
2081  {
2082  xaccQueryAddNumberMatch (q, xaccTransGetNum (trans),
2083  TRUE, FALSE, QOF_COMPARE_CONTAINS, QOF_QUERY_AND);
2084  }
2085 
2086  if (xaccSplitGetAction(s) && *xaccSplitGetAction(s) != '\0')
2087  {
2088  xaccQueryAddActionMatch (q, xaccSplitGetAction (s),
2089  TRUE, FALSE, QOF_COMPARE_CONTAINS, QOF_QUERY_AND);
2090  }
2091 
2092  n = xaccSplitGetValue (s);
2093  xaccQueryAddValueMatch (q, n, QOF_NUMERIC_MATCH_ANY,
2094  QOF_COMPARE_EQUAL, QOF_QUERY_AND);
2095 
2096  n = xaccSplitGetAmount (s);
2097  xaccQueryAddSharesMatch (q, n, QOF_COMPARE_EQUAL, QOF_QUERY_AND);
2098 
2099  if (include_price)
2100  {
2101  n = xaccSplitGetSharePrice (s);
2102  xaccQueryAddSharePriceMatch (q, n, QOF_COMPARE_EQUAL, QOF_QUERY_AND);
2103  }
2104 
2105  {
2106  Timespec ts;
2107 
2108  xaccTransGetDatePostedTS (trans, &ts);
2109  xaccQueryAddDateMatchTS (q, TRUE, ts, TRUE, ts, QOF_QUERY_AND);
2110  }
2111 
2112  if (xaccSplitGetMemo(s) && *xaccSplitGetMemo(s) != '\0')
2113  {
2114  xaccQueryAddMemoMatch (q, xaccSplitGetMemo (s), TRUE, FALSE, QOF_COMPARE_CONTAINS, QOF_QUERY_AND);
2115  }
2116 
2117  {
2118  cleared_match_t how;
2119 
2120  switch (xaccSplitGetReconcile (s))
2121  {
2122  case NREC:
2123  how = CLEARED_NO;
2124  break;
2125  case CREC:
2126  how = CLEARED_CLEARED;
2127  break;
2128  case YREC:
2129  how = CLEARED_RECONCILED;
2130  break;
2131  case FREC:
2132  how = CLEARED_FROZEN;
2133  break;
2134  case VREC:
2135  how = CLEARED_VOIDED;
2136  break;
2137  default:
2138  failure ("bad reconcile flag");
2139  qof_query_destroy (q);
2140  return NULL;
2141  }
2142 
2143  xaccQueryAddClearedMatch (q, how, QOF_QUERY_AND);
2144  }
2145  }
2146 
2147  if (query_types & ACCOUNT_QT)
2148  {
2149  GList * list;
2150  GList * node;
2151 
2152  /* QOF_GUID_MATCH_ALL */
2153  list = NULL;
2154  for (node = xaccTransGetSplitList (trans); node; node = node->next)
2155  {
2156  Split * split = node->data;
2157  list = g_list_prepend (list, xaccSplitGetAccount (split));
2158  }
2159  xaccQueryAddAccountMatch (q, list, QOF_GUID_MATCH_ALL, QOF_QUERY_AND);
2160  g_list_free (list);
2161 
2162  /* QOF_GUID_MATCH_NONE */
2163  list = NULL;
2164  list = g_list_prepend (list, get_random_guid ());
2165  list = g_list_prepend (list, get_random_guid ());
2166  list = g_list_prepend (list, get_random_guid ());
2167  xaccQueryAddAccountGUIDMatch (q, list, QOF_GUID_MATCH_NONE, QOF_QUERY_AND);
2168 
2169  /* QOF_GUID_MATCH_ANY */
2170  {
2171  GncGUID * guid = get_random_guid ();
2172  *guid = *xaccAccountGetGUID (a);
2173  list = g_list_prepend (list, guid);
2174  }
2175  xaccQueryAddAccountGUIDMatch (q, list, QOF_GUID_MATCH_ANY, QOF_QUERY_AND);
2176 
2177  for (node = list; node; node = node->next)
2178  g_free (node->data);
2179  g_list_free (list);
2180  }
2181 
2182  if (query_types & GUID_QT)
2183  {
2184  xaccQueryAddGUIDMatch (q, xaccSplitGetGUID (s),
2185  GNC_ID_SPLIT, QOF_QUERY_AND);
2186 
2187  xaccQueryAddGUIDMatch (q, xaccTransGetGUID (trans),
2188  GNC_ID_TRANS, QOF_QUERY_AND);
2189 
2190  xaccQueryAddGUIDMatch (q, xaccAccountGetGUID (a),
2191  GNC_ID_ACCOUNT, QOF_QUERY_AND);
2192  }
2193 
2194  if (query_types & SPLIT_KVP_QT)
2195  add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (s)), GNC_ID_SPLIT);
2196 
2197  if (query_types & TRANS_KVP_QT)
2198  add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (trans)), GNC_ID_TRANS);
2199 
2200  if (query_types & ACCOUNT_KVP_QT)
2201  add_kvp_query (q, qof_instance_get_slots (QOF_INSTANCE (a)), GNC_ID_ACCOUNT);
2202 
2203  return q;
2204 }
2205 
2206 static Recurrence*
2207 daily_freq(const GDate* start, int multiplier)
2208 {
2209  Recurrence *r = g_new0(Recurrence, 1);
2210  recurrenceSet(r, multiplier, PERIOD_DAY, start, WEEKEND_ADJ_NONE);
2211  return r;
2212 }
2213 
2214 static Recurrence*
2215 once_freq(const GDate *when)
2216 {
2217  Recurrence *r = g_new0(Recurrence, 1);
2218  recurrenceSet(r, 1, PERIOD_ONCE, when, WEEKEND_ADJ_NONE);
2219  return r;
2220 }
2221 
2222 static SchedXaction*
2223 add_sx(gchar *name, const GDate *start, const GDate *end, const GDate *last_occur, Recurrence *r)
2224 {
2225  QofBook *book = qof_session_get_book(gnc_get_current_session());
2227  xaccSchedXactionSetName(sx, name);
2228  xaccSchedXactionSetStartDate(sx, start);
2229  if (end != NULL)
2230  xaccSchedXactionSetEndDate(sx, end);
2231  if (last_occur != NULL)
2232  xaccSchedXactionSetLastOccurDate(sx, last_occur);
2233  {
2234  GList *recurrences = NULL;
2235  recurrences = g_list_append(recurrences, r);
2236  gnc_sx_set_schedule(sx, recurrences);
2237  }
2238 
2239  gnc_sxes_add_sx(gnc_book_get_schedxactions(book), sx);
2240 
2241  return sx;
2242 }
2243 
2244 SchedXaction*
2245 add_daily_sx(gchar *name, const GDate *start, const GDate *end, const GDate *last_occur)
2246 {
2247  return add_sx(name, start, end, last_occur, daily_freq(start, 1));
2248 }
2249 
2250 SchedXaction*
2251 add_once_sx(gchar *name, const GDate *when)
2252 {
2253  return add_sx(name, when, NULL, NULL, once_freq(when));
2254 }
2255 
2256 void
2257 remove_sx(SchedXaction *sx)
2258 {
2259  QofBook *book = qof_session_get_book(gnc_get_current_session());
2260  SchedXactions *sxes = gnc_book_get_schedxactions(book);
2261  gnc_sxes_del_sx(sxes, sx);
2262 }
void xaccAccountSetType(Account *acc, GNCAccountType tip)
Definition: Account.c:2208
void xaccSplitSetValue(Split *s, gnc_numeric amt)
Definition: Split.c:1294
gnc_commodity * gnc_commodity_table_insert(gnc_commodity_table *table, gnc_commodity *comm)
GNCPrice * gnc_price_create(QofBook *book)
Definition: gnc-pricedb.c:236
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
void guid_replace(GncGUID *guid)
void gnc_sx_set_schedule(SchedXaction *sx, GList *schedule)
Definition: SchedXaction.c:565
gnc_commodity_table * gnc_commodity_table_get_table(QofBook *book)
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
void xaccSplitSetAction(Split *split, const char *actn)
Definition: Split.c:1793
int gnc_commodity_get_fraction(const gnc_commodity *cm)
void gnc_account_append_child(Account *new_parent, Account *child)
Definition: Account.c:2525
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
SplitList * xaccAccountGetSplitList(const Account *acc)
Definition: Account.c:3717
void qof_query_set_sort_order(QofQuery *q, QofQueryParamList *primary_sort_params, QofQueryParamList *secondary_sort_params, QofQueryParamList *tertiary_sort_params)
gboolean xaccSplitDestroy(Split *split)
Definition: Split.c:1492
gnc_numeric gnc_numeric_neg(gnc_numeric a)
KvpValueType
possible types in the union KvpValue
Definition: kvp_frame.h:93
void gnc_price_unref(GNCPrice *p)
Definition: gnc-pricedb.c:272
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
Definition: gnc-pricedb.c:1053
void gnc_commodity_set_fraction(gnc_commodity *cm, int fraction)
char xaccSplitGetReconcile(const Split *split)
Definition: Split.c:1980
gboolean gnc_commodity_equal(const gnc_commodity *a, const gnc_commodity *b)
void xaccAccountSetCode(Account *acc, const char *str)
Definition: Account.c:2249
QofBook * qof_book_new(void)
void xaccTransSetDescription(Transaction *trans, const char *desc)
Definition: Transaction.c:2085
void xaccTransSetNum(Transaction *trans, const char *xnum)
Definition: Transaction.c:2065
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
void xaccSplitSetReconcile(Split *split, char recn)
Definition: Split.c:1826
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
void qof_query_set_sort_increasing(QofQuery *q, gboolean prim_inc, gboolean sec_inc, gboolean tert_inc)
const char * xaccTransGetNum(const Transaction *trans)
Definition: Transaction.c:2178
struct _QofQuery QofQuery
Definition: qofquery.h:90
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Definition: gnc-pricedb.c:872
void kvp_frame_delete(KvpFrame *frame)
void xaccTransSetDateEnteredTS(Transaction *trans, const Timespec *ts)
Definition: Transaction.c:1988
Definition: guid.h:65
gboolean gnc_numeric_negative_p(gnc_numeric a)
#define VREC
Definition: Split.h:71
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Definition: Transaction.c:1354
void qof_query_set_max_results(QofQuery *q, int n)
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
void xaccAccountDestroy(Account *acc)
Definition: Account.c:1400
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
Definition: Transaction.c:1024
const gchar * QofIdType
Definition: qofid.h:85
#define xaccAccountGetGUID(X)
Definition: Account.h:239
void xaccSplitSetAmount(Split *s, gnc_numeric amt)
Definition: Split.c:1258
QofBook * qof_session_get_book(const QofSession *session)
Account handling public routines.
void qof_query_destroy(QofQuery *q)
void xaccTransVoid(Transaction *trans, const char *reason)
Definition: Transaction.c:2495
#define YREC
Definition: Split.h:68
void xaccSplitSetMemo(Split *split, const char *memo)
Definition: Split.c:1774
GList * gnc_commodity_table_get_namespaces(const gnc_commodity_table *table)
void gnc_commodity_set_cusip(gnc_commodity *cm, const char *cusip)
#define FREC
Definition: Split.h:69
gnc_commodity * gnc_commodity_new(QofBook *book, const char *fullname, const char *name_space, const char *mnemonic, const char *cusip, int fraction)
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
gboolean gnc_pricedb_foreach_price(GNCPriceDB *db, gboolean(*f)(GNCPrice *p, gpointer user_data), gpointer user_data, gboolean stable_order)
Definition: gnc-pricedb.c:2344
void kvp_frame_set_slot_nc(KvpFrame *frame, const gchar *key, KvpValue *value)
#define kvp_value_new_gnc_numeric
Definition: kvp_frame.h:466
gboolean gnc_commodity_namespace_is_iso(const char *name_space)
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
gnc_numeric gnc_numeric_div(gnc_numeric x, gnc_numeric y, gint64 denom, gint how)
#define xaccSplitGetGUID(X)
Definition: Split.h:521
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
gnc_numeric xaccSplitGetSharePrice(const Split *split)
Definition: Split.c:1999
void xaccTransUnvoid(Transaction *trans)
Definition: Transaction.c:2552
All type declarations for the whole Gnucash engine.
#define CREC
Definition: Split.h:67
gboolean gnc_numeric_positive_p(gnc_numeric a)
gboolean gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p)
Definition: gnc-pricedb.c:1160
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
#define xaccTransGetGUID(X)
Definition: Transaction.h:755
GList * gnc_account_get_descendants(const Account *account)
Definition: Account.c:2755
CommodityList * gnc_commodity_table_get_commodities(const gnc_commodity_table *table, const char *name_space)
void xaccSchedXactionSetName(SchedXaction *sx, const gchar *newName)
Definition: SchedXaction.c:581
QofQueryOp
Definition: qofquery.h:93
gboolean xaccTransGetVoidStatus(const Transaction *trans)
Definition: Transaction.c:2526
void kvp_frame_for_each_slot(KvpFrame *f, void(*proc)(const gchar *key, KvpValue *value, gpointer data), gpointer data)
void gnc_commodity_set_fullname(gnc_commodity *cm, const char *fullname)
KvpValue * kvp_value_new_glist_nc(GList *lst)
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Definition: Account.c:4004
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
void gnc_commodity_set_mnemonic(gnc_commodity *cm, const char *mnemonic)
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
#define xaccAccountInsertSplit(acc, s)
Definition: Account.h:972
struct KvpFrameImpl KvpFrame
Definition: kvp_frame.h:76
#define QUERY_DEFAULT_SORT
Definition: qofquery.h:106
Account * xaccMallocAccount(QofBook *book)
Definition: Account.c:1083
void xaccSplitSetDateReconciledTS(Split *split, Timespec *ts)
Definition: Split.c:1865
void gnc_commodity_table_remove(gnc_commodity_table *table, gnc_commodity *comm)
void gnc_commodity_set_namespace(gnc_commodity *cm, const char *name_space)
GNCNumericErrorCode gnc_numeric_check(gnc_numeric a)
KvpFrame * kvp_frame_new(void)
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
const char * xaccSplitGetAction(const Split *split)
Definition: Split.c:1974
SchedXaction * xaccSchedXactionMalloc(QofBook *book)
Definition: SchedXaction.c:404
KvpFrame * kvp_value_get_frame(const KvpValue *value)
guint gnc_commodity_table_get_size(const gnc_commodity_table *tbl)
void xaccAccountSetDescription(Account *acc, const char *str)
Definition: Account.c:2268
void kvp_value_delete(KvpValue *value)
Scheduled Transactions public handling routines.
void xaccSchedXactionSetEndDate(SchedXaction *sx, const GDate *newEnd)
Definition: SchedXaction.c:635
#define GNC_DENOM_AUTO
Definition: gnc-numeric.h:246
API for Transactions and Splits (journal entries)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
struct KvpValueImpl KvpValue
Definition: kvp_frame.h:80
void xaccAccountSetName(Account *acc, const char *str)
Definition: Account.c:2229
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
void xaccTransRollbackEdit(Transaction *trans)
Definition: Transaction.c:1661
void xaccTransGetDatePostedTS(const Transaction *trans, Timespec *ts)
Definition: Transaction.c:2229
void xaccTransSetDatePostedTS(Transaction *trans, const Timespec *ts)
Definition: Transaction.c:1970
void xaccAccountSetCommodity(Account *acc, gnc_commodity *com)
Definition: Account.c:2389
#define NREC
Definition: Split.h:70
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987