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