QOF  0.8.7
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 
26 #include <sys/types.h>
27 #include <dirent.h>
28 #include <fcntl.h>
29 #include <glib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include "config.h"
36 #include "qof.h"
37 #include "test-engine-stuff.h"
38 #include "test-stuff.h"
39 
40 static gboolean glist_strings_only = FALSE;
41 
42 static GHashTable *exclude_kvp_types = NULL;
43 static gint kvp_max_depth = 5;
44 static gint kvp_frame_max_elements = 10;
45 
46 gboolean gnc_engine_debug_random = FALSE;
47 
48 /* ========================================================== */
49 /* Set control parameters governing the run. */
50 
51 void
52 set_max_kvp_depth (gint max_kvp_depth)
53 {
54  kvp_max_depth = MAX (max_kvp_depth, 1);
55 }
56 
57 void
58 set_max_kvp_frame_elements (gint max_kvp_frame_elements)
59 {
60  kvp_frame_max_elements = MAX (max_kvp_frame_elements, 1);
61 }
62 
63 void
64 kvp_exclude_type (KvpValueType kvp_type)
65 {
66  gint *key;
67 
68  if (!exclude_kvp_types)
69  exclude_kvp_types = g_hash_table_new (g_int_hash, g_int_equal);
70 
71  key = g_new (gint, 1);
72  *key = kvp_type;
73 
74  g_hash_table_insert (exclude_kvp_types, key, exclude_kvp_types);
75 }
76 
77 static gboolean
78 kvp_type_excluded (KvpValueType kvp_type)
79 {
80  gint key = kvp_type;
81 
82  if (!exclude_kvp_types)
83  return FALSE;
84 
85  if (g_hash_table_lookup (exclude_kvp_types, &key))
86  return TRUE;
87 
88  return FALSE;
89 }
90 
91 void
92 random_glist_strings_only (gboolean strings_only)
93 {
94  glist_strings_only = strings_only;
95 }
96 
97 
98 /* ========================================================== */
99 
100 static gint borked = 80;
101 
102 static inline gboolean
103 do_bork (void)
104 {
105  if (1 == get_random_int_in_range (0, borked))
106  {
107  return TRUE;
108  }
109  return FALSE;
110 }
111 
112 /* ========================================================== */
113 /* GList stuff */
114 /*
115 static gpointer
116 get_random_list_element (GList *list)
117 {
118  g_return_val_if_fail (list, NULL);
119 
120  return g_list_nth_data (list,
121  get_random_int_in_range (0,
122  g_list_length (list) - 1));
123 }
124 */
125 static KvpValue *get_random_kvp_value_depth (int type, gint depth);
126 
127 static GList *
128 get_random_glist_depth (gint depth)
129 {
130  GList *ret = NULL;
131  int count = get_random_int_in_range (1, 5);
132  int i;
133 
134  if (depth >= kvp_max_depth)
135  return NULL;
136 
137  for (i = 0; i < count; i++)
138  {
139  KvpValueType kvpt;
140  KvpValue *value;
141 
142  kvpt = glist_strings_only ? KVP_TYPE_STRING : -2;
143 
144  do
145  {
146  value = get_random_kvp_value_depth (kvpt, depth + 1);
147  }
148  while (!value);
149 
150  ret = g_list_prepend (ret, value);
151  }
152 
153  return ret;
154 }
155 
156 GList *
157 get_random_glist (void)
158 {
159  return get_random_glist_depth (0);
160 }
161 
162 /* ========================================================== */
163 /* Time/Date, GUID, binary data stuff */
164 
165 GUID *
166 get_random_guid (void)
167 {
168  GUID *ret;
169 
170  ret = g_new (GUID, 1);
171  guid_new (ret);
172 
173  return ret;
174 }
175 
176 bin_data *
177 get_random_binary_data (void)
178 {
179  int len;
180  bin_data *ret;
181 
182  len = get_random_int_in_range (20, 100);
183  ret = g_new (bin_data, 1);
184  ret->data = g_new (guchar, len);
185  ret->len = len;
186 
187  for (len--; len >= 0; len--)
188  {
189  ret->data[len] = (guchar) get_random_int_in_range (0, 255);
190  }
191 
192  return ret;
193 }
194 
195 /* ========================================================== */
196 /* KVP stuff */
197 
198 static KvpFrame *get_random_kvp_frame_depth (gint depth);
199 
200 static KvpValue *
201 get_random_kvp_value_depth (int type, gint depth)
202 {
203  int datype = type;
204  KvpValue *ret;
205 
206  if (datype == -1)
207  {
208  datype = get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME);
209  }
210 
211  if (datype == -2)
212  {
213  datype =
214  get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME - 1);
215  }
216 
217  if (datype == KVP_TYPE_FRAME && depth >= kvp_max_depth)
218  return NULL;
219 
220  if (datype == KVP_TYPE_GLIST && depth >= kvp_max_depth)
221  return NULL;
222 
223  if (kvp_type_excluded (datype))
224  return NULL;
225 
226  switch (datype)
227  {
228  case KVP_TYPE_GINT64:
229  ret = kvp_value_new_gint64 (get_random_gint64 ());
230  break;
231 
232  case KVP_TYPE_DOUBLE:
233  ret = NULL;
234  break;
235 
236  case KVP_TYPE_NUMERIC:
237  ret = kvp_value_new_numeric (get_random_qof_numeric ());
238  break;
239 
240  case KVP_TYPE_STRING:
241  {
242  gchar *tmp_str;
243  tmp_str = get_random_string ();
244  if (!tmp_str)
245  return NULL;
246 
247  ret = kvp_value_new_string (tmp_str);
248  g_free (tmp_str);
249  }
250  break;
251 
252  case KVP_TYPE_GUID:
253  {
254  GUID *tmp_guid;
255  tmp_guid = get_random_guid ();
256  ret = kvp_value_new_guid (tmp_guid);
257  g_free (tmp_guid);
258  }
259  break;
260  case KVP_TYPE_BINARY:
261  {
262  bin_data *tmp_data;
263  tmp_data = get_random_binary_data ();
264  ret = kvp_value_new_binary (tmp_data->data, tmp_data->len);
265  g_free (tmp_data->data);
266  g_free (tmp_data);
267  }
268  break;
269 
270  case KVP_TYPE_GLIST:
271  ret = kvp_value_new_glist_nc (get_random_glist_depth (depth + 1));
272  break;
273 
274  case KVP_TYPE_FRAME:
275  {
276  KvpFrame *tmp_frame;
277  tmp_frame = get_random_kvp_frame_depth (depth + 1);
278  ret = kvp_value_new_frame (tmp_frame);
279  kvp_frame_delete (tmp_frame);
280  }
281  break;
282 
283  default:
284  ret = NULL;
285  break;
286  }
287  return ret;
288 }
289 
290 static KvpFrame *
291 get_random_kvp_frame_depth (gint depth)
292 {
293  KvpFrame *ret;
294  int vals_to_add;
295  gboolean val_added;
296 
297  if (depth >= kvp_max_depth)
298  return NULL;
299 
300  ret = kvp_frame_new ();
301 
302  vals_to_add = get_random_int_in_range (1, kvp_frame_max_elements);
303  val_added = FALSE;
304 
305  for (; vals_to_add > 0; vals_to_add--)
306  {
307  gchar *key;
308  KvpValue *val;
309 
310  key = NULL;
311  while (key == NULL)
312  {
313  key = get_random_string_without ("/");
314  if (*key == '\0')
315  {
316  g_free (key);
317  key = NULL;
318  }
319  }
320 
321  val = get_random_kvp_value_depth (-1, depth + 1);
322  if (!val)
323  {
324  g_free (key);
325  if (!val_added)
326  vals_to_add++;
327  continue;
328  }
329 
330  val_added = TRUE;
331 
332  kvp_frame_set_slot_nc (ret, key, val);
333 
334  g_free (key);
335  }
336 
337  return ret;
338 }
339 
340 KvpFrame *
341 get_random_kvp_frame (void)
342 {
343  return get_random_kvp_frame_depth (0);
344 }
345 
346 KvpValue *
347 get_random_kvp_value (int type)
348 {
349  return get_random_kvp_value_depth (type, 0);
350 }
351 
352 /* ================================================================= */
353 /* Numeric stuff */
354 
355 #define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX)
356 
358 get_random_qof_numeric (void)
359 {
360  gint64 numer;
361  gint64 deno;
362 
363  if (RAND_MAX / 8 > rand ())
364  {
365  /* Random number between 1 and 6000 */
366  deno = RAND_IN_RANGE (6000ULL);
367  }
368  else
369  {
370  gint64 norm = RAND_IN_RANGE (10ULL);
371 
372  /* multiple of 10, between 1 and 10 000 million */
373  deno = 1;
374  while (norm)
375  {
376  deno *= 10;
377  norm--;
378  }
379  }
380 
381  /* Arbitrary random numbers can cause pointless overflow
382  * during calculations. Limit dynamic range in hopes
383  * of avoiding overflow. */
384  numer = get_random_gint64 () / 100000;
385  if (0 == numer)
386  numer = 1;
387  return qof_numeric_create (numer, deno);
388 }
389 
390 /*
391 static GList *
392 get_random_guids(int max)
393 {
394  GList *guids = NULL;
395  int num_guids;
396 
397  if (max < 1) return NULL;
398 
399  num_guids = get_random_int_in_range (1, max);
400 
401  while (num_guids-- > 0)
402  g_list_prepend (guids, get_random_guid ());
403 
404  return guids;
405  }
406 *//*
407  static void
408  free_random_guids(GList *guids)
409  {
410  GList *node;
411 
412  for (node = guids; node; node = node->next)
413  g_free (node->data);
414 
415  g_list_free (guids);
416  }
417  *//*
418  static QofQueryOp
419  get_random_queryop(void)
420  {
421  QofQueryOp op = get_random_int_in_range (1, QOF_QUERY_XOR);
422  if (gnc_engine_debug_random) printf ("op = %d, ", op);
423  return op;
424  }
425  *//*
426  static GSList *
427  get_random_kvp_path (void)
428  {
429  GSList *path;
430  gint len;
431 
432  path = NULL;
433  len = get_random_int_in_range (1, kvp_max_depth);
434 
435  while (len--)
436  path = g_slist_prepend (path, get_random_string ());
437 
438  return g_slist_reverse (path);
439  }
440  *//*
441  static void
442  free_random_kvp_path (GSList *path)
443  {
444  GSList *node;
445 
446  for (node = path; node; node = node->next)
447  g_free (node->data);
448 
449  g_slist_free (path);
450  }
451  */
452 typedef enum
453 {
454  BY_STANDARD = 1,
455  BY_DATE,
456  BY_DATE_ENTERED,
457  BY_DATE_RECONCILED,
458  BY_NUM,
459  BY_AMOUNT,
460  BY_MEMO,
461  BY_DESC,
462  BY_NONE
463 } sort_type_t;
464 
465 typedef struct
466 {
467  QofIdType where;
468  GSList *path;
469  QofQuery *q;
470 } KVPQueryData;
471 
472 TestQueryTypes
473 get_random_query_type (void)
474 {
475  switch (get_random_int_in_range (0, 4))
476  {
477  case 0:
478  return SIMPLE_QT;
479  case 4:
480  return GUID_QT;
481  default:
482  return SIMPLE_QT;
483  }
484 }
const gchar * QofIdType
Definition: qofid.h:81
KvpValueType
possible types in the union KvpValue
Definition: kvpframe.h:87
Unique identifier.
Definition: kvpframe.h:118
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
This file declares testing functions for the engine.
struct _QofQuery QofQuery
Definition: qofquery.h:85
128bit denominator/numerator maths.
Definition: kvpframe.h:106
void kvp_frame_delete(KvpFrame *frame)
Definition: kvpframe.c:115
struct _KvpValue KvpValue
Definition: kvpframe.h:78
64bit integer
Definition: kvpframe.h:94
static QofNumeric qof_numeric_create(gint64 num, gint64 denom)
Definition: qofnumeric.h:243
void kvp_frame_set_slot_nc(KvpFrame *frame, const gchar *slot, KvpValue *value)
Definition: kvpframe.c:697
Definition: guid.h:53
void guid_new(GUID *guid)
Definition: guid.c:444
KvpValue * kvp_value_new_glist_nc(GList *value)
Definition: kvpframe.c:1319
standard C string
Definition: kvpframe.h:112
KvpFrame * kvp_frame_new(void)
Definition: kvpframe.c:97
standard C double type
Definition: kvpframe.h:100