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
17 /**
18 * @file test-engine-stuff.c
19 * @brief tools to set up random test data.
20 *
21 * Created by Linux Developers Group, 2001
22 * Updates Linas Vepstas July 2004
23 \todo replace with g_test routines from 2.16
24 */
25
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
set_max_kvp_depth(gint max_kvp_depth)52 set_max_kvp_depth (gint max_kvp_depth)
53 {
54 kvp_max_depth = MAX (max_kvp_depth, 1);
55 }
56
57 void
set_max_kvp_frame_elements(gint max_kvp_frame_elements)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
kvp_exclude_type(KvpValueType kvp_type)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
kvp_type_excluded(KvpValueType kvp_type)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
random_glist_strings_only(gboolean strings_only)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
do_bork(void)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 *
get_random_glist_depth(gint depth)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 *
get_random_glist(void)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 *
get_random_guid(void)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 *
get_random_binary_data(void)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 *
get_random_kvp_value_depth(int type,gint depth)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 *
get_random_kvp_frame_depth(gint depth)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 *
get_random_kvp_frame(void)341 get_random_kvp_frame (void)
342 {
343 return get_random_kvp_frame_depth (0);
344 }
345
346 KvpValue *
get_random_kvp_value(int type)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
357 QofNumeric
get_random_qof_numeric(void)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
get_random_query_type(void)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 }
485