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