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