QOF 0.7.5
|
00001 /* 00002 * This program is free software; you can redistribute it and/or modify 00003 * it under the terms of the GNU General Public License as published by 00004 * the Free Software Foundation; either version 2 of the License, or 00005 * (at your option) any later version. 00006 * 00007 * This program is distributed in the hope that it will be useful, 00008 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00009 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00010 * GNU General Public License for more details. 00011 * 00012 * You should have received a copy of the GNU General Public License 00013 * along with this program; if not, write to the Free Software 00014 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301, USA 00015 */ 00016 00025 #include <sys/types.h> 00026 #include <dirent.h> 00027 #include <fcntl.h> 00028 #include <glib.h> 00029 #include <stdio.h> 00030 #include <stdlib.h> 00031 #include <string.h> 00032 #include <sys/stat.h> 00033 #include <unistd.h> 00034 #include "config.h" 00035 #include "qof.h" 00036 #include "test-engine-stuff.h" 00037 #include "test-stuff.h" 00038 00039 static gboolean glist_strings_only = FALSE; 00040 00041 static GHashTable *exclude_kvp_types = NULL; 00042 static gint kvp_max_depth = 5; 00043 static gint kvp_frame_max_elements = 10; 00044 00045 gboolean gnc_engine_debug_random = FALSE; 00046 00047 /* ========================================================== */ 00048 /* Set control parameters governing the run. */ 00049 00050 void 00051 set_max_kvp_depth (gint max_kvp_depth) 00052 { 00053 kvp_max_depth = MAX (max_kvp_depth, 1); 00054 } 00055 00056 void 00057 set_max_kvp_frame_elements (gint max_kvp_frame_elements) 00058 { 00059 kvp_frame_max_elements = MAX (max_kvp_frame_elements, 1); 00060 } 00061 00062 void 00063 kvp_exclude_type (KvpValueType kvp_type) 00064 { 00065 gint *key; 00066 00067 if (!exclude_kvp_types) 00068 exclude_kvp_types = g_hash_table_new (g_int_hash, g_int_equal); 00069 00070 key = g_new (gint, 1); 00071 *key = kvp_type; 00072 00073 g_hash_table_insert (exclude_kvp_types, key, exclude_kvp_types); 00074 } 00075 00076 static gboolean 00077 kvp_type_excluded (KvpValueType kvp_type) 00078 { 00079 gint key = kvp_type; 00080 00081 if (!exclude_kvp_types) 00082 return FALSE; 00083 00084 if (g_hash_table_lookup (exclude_kvp_types, &key)) 00085 return TRUE; 00086 00087 return FALSE; 00088 } 00089 00090 void 00091 random_glist_strings_only (gboolean strings_only) 00092 { 00093 glist_strings_only = strings_only; 00094 } 00095 00096 00097 #ifndef QOF_DISABLE_DEPRECATED 00098 static gboolean zero_nsec = FALSE; 00099 00100 void 00101 random_timespec_zero_nsec (gboolean zero_nsec_in) 00102 { 00103 zero_nsec = zero_nsec_in; 00104 } 00105 00106 static gboolean usec_resolution = FALSE; 00107 00108 void 00109 random_timespec_usec_resolution (gboolean usec_resolution_in) 00110 { 00111 usec_resolution = usec_resolution_in; 00112 } 00113 #endif 00114 /* ========================================================== */ 00115 00116 static gint borked = 80; 00117 00118 static inline gboolean 00119 do_bork (void) 00120 { 00121 if (1 == get_random_int_in_range (0, borked)) 00122 { 00123 return TRUE; 00124 } 00125 return FALSE; 00126 } 00127 00128 /* ========================================================== */ 00129 /* GList stuff */ 00130 /* 00131 static gpointer 00132 get_random_list_element (GList *list) 00133 { 00134 g_return_val_if_fail (list, NULL); 00135 00136 return g_list_nth_data (list, 00137 get_random_int_in_range (0, 00138 g_list_length (list) - 1)); 00139 } 00140 */ 00141 static KvpValue *get_random_kvp_value_depth (int type, gint depth); 00142 00143 static GList * 00144 get_random_glist_depth (gint depth) 00145 { 00146 GList *ret = NULL; 00147 int count = get_random_int_in_range (1, 5); 00148 int i; 00149 00150 if (depth >= kvp_max_depth) 00151 return NULL; 00152 00153 for (i = 0; i < count; i++) 00154 { 00155 KvpValueType kvpt; 00156 KvpValue *value; 00157 00158 kvpt = glist_strings_only ? KVP_TYPE_STRING : -2; 00159 00160 do 00161 { 00162 value = get_random_kvp_value_depth (kvpt, depth + 1); 00163 } 00164 while (!value); 00165 00166 ret = g_list_prepend (ret, value); 00167 } 00168 00169 return ret; 00170 } 00171 00172 GList * 00173 get_random_glist (void) 00174 { 00175 return get_random_glist_depth (0); 00176 } 00177 00178 /* ========================================================== */ 00179 /* Time/Date, GUID, binary data stuff */ 00180 #ifndef QOF_DISABLE_DEPRECATED 00181 Timespec * 00182 get_random_timespec (void) 00183 { 00184 Timespec *ret; 00185 00186 ret = g_new0 (Timespec, 1); 00187 00188 while (ret->tv_sec <= 0) 00189 ret->tv_sec = rand (); 00190 00191 if (zero_nsec) 00192 ret->tv_nsec = 0; 00193 else 00194 { 00195 ret->tv_nsec = rand (); 00196 00197 if (usec_resolution) 00198 { 00199 ret->tv_nsec = MIN (ret->tv_nsec, 999999999); 00200 ret->tv_nsec /= 1000; 00201 ret->tv_nsec *= 1000; 00202 } 00203 } 00204 00205 return ret; 00206 } 00207 #endif 00208 00209 GUID * 00210 get_random_guid (void) 00211 { 00212 GUID *ret; 00213 00214 ret = g_new (GUID, 1); 00215 guid_new (ret); 00216 00217 return ret; 00218 } 00219 00220 bin_data * 00221 get_random_binary_data (void) 00222 { 00223 int len; 00224 bin_data *ret; 00225 00226 len = get_random_int_in_range (20, 100); 00227 ret = g_new (bin_data, 1); 00228 ret->data = g_new (guchar, len); 00229 ret->len = len; 00230 00231 for (len--; len >= 0; len--) 00232 { 00233 ret->data[len] = (guchar) get_random_int_in_range (0, 255); 00234 } 00235 00236 return ret; 00237 } 00238 00239 /* ========================================================== */ 00240 /* KVP stuff */ 00241 00242 static KvpFrame *get_random_kvp_frame_depth (gint depth); 00243 00244 static KvpValue * 00245 get_random_kvp_value_depth (int type, gint depth) 00246 { 00247 int datype = type; 00248 KvpValue *ret; 00249 00250 if (datype == -1) 00251 { 00252 datype = get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME); 00253 } 00254 00255 if (datype == -2) 00256 { 00257 datype = 00258 get_random_int_in_range (KVP_TYPE_GINT64, KVP_TYPE_FRAME - 1); 00259 } 00260 00261 if (datype == KVP_TYPE_FRAME && depth >= kvp_max_depth) 00262 return NULL; 00263 00264 if (datype == KVP_TYPE_GLIST && depth >= kvp_max_depth) 00265 return NULL; 00266 00267 if (kvp_type_excluded (datype)) 00268 return NULL; 00269 00270 switch (datype) 00271 { 00272 case KVP_TYPE_GINT64: 00273 ret = kvp_value_new_gint64 (get_random_gint64 ()); 00274 break; 00275 00276 case KVP_TYPE_DOUBLE: 00277 ret = NULL; 00278 break; 00279 00280 case KVP_TYPE_NUMERIC: 00281 ret = kvp_value_new_numeric (get_random_qof_numeric ()); 00282 break; 00283 00284 case KVP_TYPE_STRING: 00285 { 00286 gchar *tmp_str; 00287 tmp_str = get_random_string (); 00288 if (!tmp_str) 00289 return NULL; 00290 00291 ret = kvp_value_new_string (tmp_str); 00292 g_free (tmp_str); 00293 } 00294 break; 00295 00296 case KVP_TYPE_GUID: 00297 { 00298 GUID *tmp_guid; 00299 tmp_guid = get_random_guid (); 00300 ret = kvp_value_new_guid (tmp_guid); 00301 g_free (tmp_guid); 00302 } 00303 break; 00304 #ifndef QOF_DISABLE_DEPRECATED 00305 case KVP_TYPE_TIMESPEC: 00306 { 00307 Timespec *ts = get_random_timespec (); 00308 ret = kvp_value_new_timespec (*ts); 00309 g_free (ts); 00310 } 00311 break; 00312 #endif 00313 case KVP_TYPE_BINARY: 00314 { 00315 bin_data *tmp_data; 00316 tmp_data = get_random_binary_data (); 00317 ret = kvp_value_new_binary (tmp_data->data, tmp_data->len); 00318 g_free (tmp_data->data); 00319 g_free (tmp_data); 00320 } 00321 break; 00322 00323 case KVP_TYPE_GLIST: 00324 ret = kvp_value_new_glist_nc (get_random_glist_depth (depth + 1)); 00325 break; 00326 00327 case KVP_TYPE_FRAME: 00328 { 00329 KvpFrame *tmp_frame; 00330 tmp_frame = get_random_kvp_frame_depth (depth + 1); 00331 ret = kvp_value_new_frame (tmp_frame); 00332 kvp_frame_delete (tmp_frame); 00333 } 00334 break; 00335 00336 default: 00337 ret = NULL; 00338 break; 00339 } 00340 return ret; 00341 } 00342 00343 static KvpFrame * 00344 get_random_kvp_frame_depth (gint depth) 00345 { 00346 KvpFrame *ret; 00347 int vals_to_add; 00348 gboolean val_added; 00349 00350 if (depth >= kvp_max_depth) 00351 return NULL; 00352 00353 ret = kvp_frame_new (); 00354 00355 vals_to_add = get_random_int_in_range (1, kvp_frame_max_elements); 00356 val_added = FALSE; 00357 00358 for (; vals_to_add > 0; vals_to_add--) 00359 { 00360 gchar *key; 00361 KvpValue *val; 00362 00363 key = NULL; 00364 while (key == NULL) 00365 { 00366 key = get_random_string_without ("/"); 00367 if (*key == '\0') 00368 { 00369 g_free (key); 00370 key = NULL; 00371 } 00372 } 00373 00374 val = get_random_kvp_value_depth (-1, depth + 1); 00375 if (!val) 00376 { 00377 g_free (key); 00378 if (!val_added) 00379 vals_to_add++; 00380 continue; 00381 } 00382 00383 val_added = TRUE; 00384 00385 kvp_frame_set_slot_nc (ret, key, val); 00386 00387 g_free (key); 00388 } 00389 00390 return ret; 00391 } 00392 00393 KvpFrame * 00394 get_random_kvp_frame (void) 00395 { 00396 return get_random_kvp_frame_depth (0); 00397 } 00398 00399 KvpValue * 00400 get_random_kvp_value (int type) 00401 { 00402 return get_random_kvp_value_depth (type, 0); 00403 } 00404 00405 /* ================================================================= */ 00406 /* Numeric stuff */ 00407 00408 #define RAND_IN_RANGE(X) (((X)*((gint64) (rand()+1)))/RAND_MAX) 00409 00410 QofNumeric 00411 get_random_qof_numeric (void) 00412 { 00413 gint64 numer; 00414 gint64 deno; 00415 00416 if (RAND_MAX / 8 > rand ()) 00417 { 00418 /* Random number between 1 and 6000 */ 00419 deno = RAND_IN_RANGE (6000ULL); 00420 } 00421 else 00422 { 00423 gint64 norm = RAND_IN_RANGE (10ULL); 00424 00425 /* multiple of 10, between 1 and 10 000 million */ 00426 deno = 1; 00427 while (norm) 00428 { 00429 deno *= 10; 00430 norm--; 00431 } 00432 } 00433 00434 /* Arbitrary random numbers can cause pointless overflow 00435 * during calculations. Limit dynamic range in hopes 00436 * of avoiding overflow. */ 00437 numer = get_random_gint64 () / 100000; 00438 if (0 == numer) 00439 numer = 1; 00440 return qof_numeric_create (numer, deno); 00441 } 00442 00443 /* 00444 static GList * 00445 get_random_guids(int max) 00446 { 00447 GList *guids = NULL; 00448 int num_guids; 00449 00450 if (max < 1) return NULL; 00451 00452 num_guids = get_random_int_in_range (1, max); 00453 00454 while (num_guids-- > 0) 00455 g_list_prepend (guids, get_random_guid ()); 00456 00457 return guids; 00458 } 00459 *//* 00460 static void 00461 free_random_guids(GList *guids) 00462 { 00463 GList *node; 00464 00465 for (node = guids; node; node = node->next) 00466 g_free (node->data); 00467 00468 g_list_free (guids); 00469 } 00470 *//* 00471 static QofQueryOp 00472 get_random_queryop(void) 00473 { 00474 QofQueryOp op = get_random_int_in_range (1, QOF_QUERY_XOR); 00475 if (gnc_engine_debug_random) printf ("op = %d, ", op); 00476 return op; 00477 } 00478 *//* 00479 static GSList * 00480 get_random_kvp_path (void) 00481 { 00482 GSList *path; 00483 gint len; 00484 00485 path = NULL; 00486 len = get_random_int_in_range (1, kvp_max_depth); 00487 00488 while (len--) 00489 path = g_slist_prepend (path, get_random_string ()); 00490 00491 return g_slist_reverse (path); 00492 } 00493 *//* 00494 static void 00495 free_random_kvp_path (GSList *path) 00496 { 00497 GSList *node; 00498 00499 for (node = path; node; node = node->next) 00500 g_free (node->data); 00501 00502 g_slist_free (path); 00503 } 00504 */ 00505 typedef enum 00506 { 00507 BY_STANDARD = 1, 00508 BY_DATE, 00509 BY_DATE_ENTERED, 00510 BY_DATE_RECONCILED, 00511 BY_NUM, 00512 BY_AMOUNT, 00513 BY_MEMO, 00514 BY_DESC, 00515 BY_NONE 00516 } sort_type_t; 00517 00518 typedef struct 00519 { 00520 QofIdType where; 00521 GSList *path; 00522 QofQuery *q; 00523 } KVPQueryData; 00524 00525 TestQueryTypes 00526 get_random_query_type (void) 00527 { 00528 switch (get_random_int_in_range (0, 4)) 00529 { 00530 case 0: 00531 return SIMPLE_QT; 00532 case 4: 00533 return GUID_QT; 00534 default: 00535 return SIMPLE_QT; 00536 } 00537 }