QOF  0.7.5
test-engine-stuff.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or modify
3  * it under the terms of the GNU General Public License as published by
4  * the Free Software Foundation; either version 2 of the License, or
5  * (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA
15  */
16 
25 #include <sys/types.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <glib.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/stat.h>
33 #include <unistd.h>
34 #include "config.h"
35 #include "qof.h"
36 #include "test-engine-stuff.h"
37 #include "test-stuff.h"
38 
39 static gboolean glist_strings_only = FALSE;
40 
41 static GHashTable *exclude_kvp_types = NULL;
42 static gint kvp_max_depth = 5;
43 static gint kvp_frame_max_elements = 10;
44 
45 gboolean gnc_engine_debug_random = FALSE;
46 
47 /* ========================================================== */
48 /* Set control parameters governing the run. */
49 
50 void
51 set_max_kvp_depth (gint max_kvp_depth)
52 {
53  kvp_max_depth = MAX (max_kvp_depth, 1);
54 }
55 
56 void
57 set_max_kvp_frame_elements (gint max_kvp_frame_elements)
58 {
59  kvp_frame_max_elements = MAX (max_kvp_frame_elements, 1);
60 }
61 
62 void
63 kvp_exclude_type (KvpValueType kvp_type)
64 {
65  gint *key;
66 
67  if (!exclude_kvp_types)
68  exclude_kvp_types = g_hash_table_new (g_int_hash, g_int_equal);
69 
70  key = g_new (gint, 1);
71  *key = kvp_type;
72 
73  g_hash_table_insert (exclude_kvp_types, key, exclude_kvp_types);
74 }
75 
76 static gboolean
77 kvp_type_excluded (KvpValueType kvp_type)
78 {
79  gint key = kvp_type;
80 
81  if (!exclude_kvp_types)
82  return FALSE;
83 
84  if (g_hash_table_lookup (exclude_kvp_types, &key))
85  return TRUE;
86 
87  return FALSE;
88 }
89 
90 void
91 random_glist_strings_only (gboolean strings_only)
92 {
93  glist_strings_only = strings_only;
94 }
95 
96 
97 #ifndef QOF_DISABLE_DEPRECATED
98 static gboolean zero_nsec = FALSE;
99 
100 void
101 random_timespec_zero_nsec (gboolean zero_nsec_in)
102 {
103  zero_nsec = zero_nsec_in;
104 }
105 
106 static gboolean usec_resolution = FALSE;
107 
108 void
109 random_timespec_usec_resolution (gboolean usec_resolution_in)
110 {
111  usec_resolution = usec_resolution_in;
112 }
113 #endif
114 /* ========================================================== */
115 
116 static gint borked = 80;
117 
118 static inline gboolean
119 do_bork (void)
120 {
121  if (1 == get_random_int_in_range (0, borked))
122  {
123  return TRUE;
124  }
125  return FALSE;
126 }
127 
128 /* ========================================================== */
129 /* GList stuff */
130 /*
131 static gpointer
132 get_random_list_element (GList *list)
133 {
134  g_return_val_if_fail (list, NULL);
135 
136  return g_list_nth_data (list,
137  get_random_int_in_range (0,
138  g_list_length (list) - 1));
139 }
140 */
141 static KvpValue *get_random_kvp_value_depth (int type, gint depth);
142 
143 static GList *
144 get_random_glist_depth (gint depth)
145 {
146  GList *ret = NULL;
147  int count = get_random_int_in_range (1, 5);
148  int i;
149 
150  if (depth >= kvp_max_depth)
151  return NULL;
152 
153  for (i = 0; i < count; i++)
154  {
155  KvpValueType kvpt;
156  KvpValue *value;
157 
158  kvpt = glist_strings_only ? KVP_TYPE_STRING : -2;
159 
160  do
161  {
162  value = get_random_kvp_value_depth (kvpt, depth + 1);
163  }
164  while (!value);
165 
166  ret = g_list_prepend (ret, value);
167  }
168 
169  return ret;
170 }
171 
172 GList *
173 get_random_glist (void)
174 {
175  return get_random_glist_depth (0);
176 }
177 
178 /* ========================================================== */
179 /* Time/Date, GUID, binary data stuff */
180 #ifndef QOF_DISABLE_DEPRECATED
181 Timespec *
182 get_random_timespec (void)
183 {
184  Timespec *ret;
185 
186  ret = g_new0 (Timespec, 1);
187 
188  while (ret->tv_sec <= 0)
189  ret->tv_sec = rand ();
190 
191  if (zero_nsec)
192  ret->tv_nsec = 0;
193  else
194  {
195  ret->tv_nsec = rand ();
196 
197  if (usec_resolution)
198  {
199  ret->tv_nsec = MIN (ret->tv_nsec, 999999999);
200  ret->tv_nsec /= 1000;
201  ret->tv_nsec *= 1000;
202  }
203  }
204 
205  return ret;
206 }
207 #endif
208 
209 GUID *
210 get_random_guid (void)
211 {
212  GUID *ret;
213 
214  ret = g_new (GUID, 1);
215  guid_new (ret);
216 
217  return ret;
218 }
219 
220 bin_data *
221 get_random_binary_data (void)
222 {
223  int len;
224  bin_data *ret;
225 
226  len = get_random_int_in_range (20, 100);
227  ret = g_new (bin_data, 1);
228  ret->data = g_new (guchar, len);
229  ret->len = len;
230 
231  for (len--; len >= 0; len--)
232  {
233  ret->data[len] = (guchar) get_random_int_in_range (0, 255);
234  }
235 
236  return ret;
237 }
238 
239 /* ========================================================== */
240 /* KVP stuff */
241 
242 static KvpFrame *get_random_kvp_frame_depth (gint depth);
243 
244 static KvpValue *
245 get_random_kvp_value_depth (int type, gint depth)
246 {
247  int datype = type;
248  KvpValue *ret;
249 
250  if (datype == -1)
251  {
252  datype = get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME);
253  }
254 
255  if (datype == -2)
256  {
257  datype =
258  get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME - 1);
259  }
260 
261  if (datype == KVP_TYPE_FRAME && depth >= kvp_max_depth)
262  return NULL;
263 
264  if (datype == KVP_TYPE_GLIST && depth >= kvp_max_depth)
265  return NULL;
266 
267  if (kvp_type_excluded (datype))
268  return NULL;
269 
270  switch (datype)
271  {
272  case KVP_TYPE_GINT64:
273  ret = kvp_value_new_gint64 (get_random_gint64 ());
274  break;
275 
276  case KVP_TYPE_DOUBLE:
277  ret = NULL;
278  break;
279 
280  case KVP_TYPE_NUMERIC:
281  ret = kvp_value_new_numeric (get_random_qof_numeric ());
282  break;
283 
284  case KVP_TYPE_STRING:
285  {
286  gchar *tmp_str;
287  tmp_str = get_random_string ();
288  if (!tmp_str)
289  return NULL;
290 
291  ret = kvp_value_new_string (tmp_str);
292  g_free (tmp_str);
293  }
294  break;
295 
296  case KVP_TYPE_GUID:
297  {
298  GUID *tmp_guid;
299  tmp_guid = get_random_guid ();
300  ret = kvp_value_new_guid (tmp_guid);
301  g_free (tmp_guid);
302  }
303  break;
304 #ifndef QOF_DISABLE_DEPRECATED
305  case KVP_TYPE_TIMESPEC:
306  {
307  Timespec *ts = get_random_timespec ();
308  ret = kvp_value_new_timespec (*ts);
309  g_free (ts);
310  }
311  break;
312 #endif
313  case KVP_TYPE_BINARY:
314  {
315  bin_data *tmp_data;
316  tmp_data = get_random_binary_data ();
317  ret = kvp_value_new_binary (tmp_data->data, tmp_data->len);
318  g_free (tmp_data->data);
319  g_free (tmp_data);
320  }
321  break;
322 
323  case KVP_TYPE_GLIST:
324  ret = kvp_value_new_glist_nc (get_random_glist_depth (depth + 1));
325  break;
326 
327  case KVP_TYPE_FRAME:
328  {
329  KvpFrame *tmp_frame;
330  tmp_frame = get_random_kvp_frame_depth (depth + 1);
331  ret = kvp_value_new_frame (tmp_frame);
332  kvp_frame_delete (tmp_frame);
333  }
334  break;
335 
336  default:
337  ret = NULL;
338  break;
339  }
340  return ret;
341 }
342 
343 static KvpFrame *
344 get_random_kvp_frame_depth (gint depth)
345 {
346  KvpFrame *ret;
347  int vals_to_add;
348  gboolean val_added;
349 
350  if (depth >= kvp_max_depth)
351  return NULL;
352 
353  ret = kvp_frame_new ();
354 
355  vals_to_add = get_random_int_in_range (1, kvp_frame_max_elements);
356  val_added = FALSE;
357 
358  for (; vals_to_add > 0; vals_to_add--)
359  {
360  gchar *key;
361  KvpValue *val;
362 
363  key = NULL;
364  while (key == NULL)
365  {
366  key = get_random_string_without ("/");
367  if (*key == '\0')
368  {
369  g_free (key);
370  key = NULL;
371  }
372  }
373 
374  val = get_random_kvp_value_depth (-1, depth + 1);
375  if (!val)
376  {
377  g_free (key);
378  if (!val_added)
379  vals_to_add++;
380  continue;
381  }
382 
383  val_added = TRUE;
384 
385  kvp_frame_set_slot_nc (ret, key, val);
386 
387  g_free (key);
388  }
389 
390  return ret;
391 }
392 
393 KvpFrame *
394 get_random_kvp_frame (void)
395 {
396  return get_random_kvp_frame_depth (0);
397 }
398 
399 KvpValue *
400 get_random_kvp_value (int type)
401 {
402  return get_random_kvp_value_depth (type, 0);
403 }
404 
405 /* ================================================================= */
406 /* Numeric stuff */
407 
408 #define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX)
409 
411 get_random_qof_numeric (void)
412 {
413  gint64 numer;
414  gint64 deno;
415 
416  if (RAND_MAX / 8 > rand ())
417  {
418  /* Random number between 1 and 6000 */
419  deno = RAND_IN_RANGE (6000ULL);
420  }
421  else
422  {
423  gint64 norm = RAND_IN_RANGE (10ULL);
424 
425  /* multiple of 10, between 1 and 10 000 million */
426  deno = 1;
427  while (norm)
428  {
429  deno *= 10;
430  norm--;
431  }
432  }
433 
434  /* Arbitrary random numbers can cause pointless overflow
435  * during calculations. Limit dynamic range in hopes
436  * of avoiding overflow. */
437  numer = get_random_gint64 () / 100000;
438  if (0 == numer)
439  numer = 1;
440  return qof_numeric_create (numer, deno);
441 }
442 
443 /*
444 static GList *
445 get_random_guids(int max)
446 {
447  GList *guids = NULL;
448  int num_guids;
449 
450  if (max < 1) return NULL;
451 
452  num_guids = get_random_int_in_range (1, max);
453 
454  while (num_guids-- > 0)
455  g_list_prepend (guids, get_random_guid ());
456 
457  return guids;
458  }
459 *//*
460  static void
461  free_random_guids(GList *guids)
462  {
463  GList *node;
464 
465  for (node = guids; node; node = node->next)
466  g_free (node->data);
467 
468  g_list_free (guids);
469  }
470  *//*
471  static QofQueryOp
472  get_random_queryop(void)
473  {
474  QofQueryOp op = get_random_int_in_range (1, QOF_QUERY_XOR);
475  if (gnc_engine_debug_random) printf ("op = %d, ", op);
476  return op;
477  }
478  *//*
479  static GSList *
480  get_random_kvp_path (void)
481  {
482  GSList *path;
483  gint len;
484 
485  path = NULL;
486  len = get_random_int_in_range (1, kvp_max_depth);
487 
488  while (len--)
489  path = g_slist_prepend (path, get_random_string ());
490 
491  return g_slist_reverse (path);
492  }
493  *//*
494  static void
495  free_random_kvp_path (GSList *path)
496  {
497  GSList *node;
498 
499  for (node = path; node; node = node->next)
500  g_free (node->data);
501 
502  g_slist_free (path);
503  }
504  */
505 typedef enum
506 {
507  BY_STANDARD = 1,
508  BY_DATE,
509  BY_DATE_ENTERED,
510  BY_DATE_RECONCILED,
511  BY_NUM,
512  BY_AMOUNT,
513  BY_MEMO,
514  BY_DESC,
515  BY_NONE
516 } sort_type_t;
517 
518 typedef struct
519 {
520  QofIdType where;
521  GSList *path;
522  QofQuery *q;
523 } KVPQueryData;
524 
525 TestQueryTypes
526 get_random_query_type (void)
527 {
528  switch (get_random_int_in_range (0, 4))
529  {
530  case 0:
531  return SIMPLE_QT;
532  case 4:
533  return GUID_QT;
534  default:
535  return SIMPLE_QT;
536  }
537 }