1#!/usr/bin/python 2 3from __future__ import print_function 4 5import os 6import sys 7import re 8import random 9 10import idl 11 12def randomize_char(c): 13 if random.random() < 0.5: 14 return str.lower(c) 15 else: 16 return str.upper(c) 17 18def randomize_case(s): 19 r = [randomize_char(c) for c in s] 20 return "".join(r) 21 22def randomize_enum(e): 23 return random.choice([v.name for v in e.values]) 24 25handcoded = ["libxl_bitmap", "libxl_key_value_list", 26 "libxl_cpuid_policy_list", "libxl_string_list"] 27 28def gen_rand_init(ty, v, indent = " ", parent = None): 29 s = "" 30 if isinstance(ty, idl.Enumeration): 31 s += "%s = %s;\n" % (ty.pass_arg(v, parent is None), randomize_enum(ty)) 32 elif isinstance(ty, idl.Array): 33 if parent is None: 34 raise Exception("Array type must have a parent") 35 s += "%s = test_rand(8);\n" % (parent + ty.lenvar.name) 36 s += "%s = calloc(%s, sizeof(*%s));\n" % \ 37 (v, parent + ty.lenvar.name, v) 38 s += "assert(%s);\n" % (v, ) 39 s += "{\n" 40 s += " int i;\n" 41 s += " for (i=0; i<%s; i++)\n" % (parent + ty.lenvar.name) 42 s += gen_rand_init(ty.elem_type, v+"[i]", 43 indent + " ", parent) 44 s += "}\n" 45 elif isinstance(ty, idl.KeyedUnion): 46 if parent is None: 47 raise Exception("KeyedUnion type must have a parent") 48 s += gen_rand_init(ty.keyvar.type, parent + ty.keyvar.name, indent, parent) 49 s += "switch (%s) {\n" % (parent + ty.keyvar.name) 50 for f in ty.fields: 51 (nparent,fexpr) = ty.member(v, f, parent is None) 52 s += "case %s:\n" % f.enumname 53 if f.type is not None: 54 s += gen_rand_init(f.type, fexpr, indent + " ", nparent) 55 s += " break;\n" 56 s += "}\n" 57 elif isinstance(ty, idl.Struct) \ 58 and (parent is None or ty.json_gen_fn is None): 59 for f in [f for f in ty.fields if not f.const]: 60 (nparent,fexpr) = ty.member(v, f, parent is None) 61 s += gen_rand_init(f.type, fexpr, "", nparent) 62 elif hasattr(ty, "rand_init") and ty.rand_init is not None: 63 s += "%s(%s);\n" % (ty.rand_init, 64 ty.pass_arg(v, isref=parent is None, 65 passby=idl.PASS_BY_REFERENCE)) 66 elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap", "libxl_ms_vm_genid"]: 67 s += "rand_bytes((uint8_t *)%s, sizeof(*%s));\n" % (v,v) 68 elif ty.typename in ["libxl_domid", "libxl_devid"] or isinstance(ty, idl.Number): 69 s += "%s = test_rand(sizeof(%s) * 8);\n" % \ 70 (ty.pass_arg(v, parent is None), 71 ty.pass_arg(v, parent is None)) 72 elif ty.typename in ["bool"]: 73 s += "%s = test_rand(2);\n" % v 74 elif ty.typename in ["libxl_defbool"]: 75 s += "libxl_defbool_set(%s, test_rand(2));\n" % v 76 elif ty.typename in ["char *"]: 77 s += "%s = rand_str();\n" % v 78 elif ty.private: 79 pass 80 elif ty.typename in handcoded: 81 raise Exception("Gen for handcoded %s" % ty.typename) 82 else: 83 raise Exception("Cannot randomly init %s" % ty.typename) 84 85 if s != "": 86 s = indent + s 87 return s.replace("\n", "\n%s" % indent).rstrip(indent) 88 89if __name__ == '__main__': 90 if len(sys.argv) < 3: 91 print("Usage: gentest.py <idl> <implementation>", file=sys.stderr) 92 sys.exit(1) 93 94 random.seed(os.getenv('LIBXL_TESTIDL_SEED')) 95 96 (builtins,types) = idl.parse(sys.argv[1]) 97 98 impl = sys.argv[2] 99 f = open(impl, "w") 100 f.write(""" 101#include <stdio.h> 102#include <stdlib.h> 103#include <string.h> 104#include <assert.h> 105 106#include "libxl.h" 107#include "libxl_utils.h" 108 109static int test_rand(unsigned max) 110{ 111 /* We are not using rand() for its cryptographic properies. */ 112 return rand() % max; 113} 114 115static char *rand_str(void) 116{ 117 int i, sz = test_rand(32); 118 char *s = malloc(sz+1); 119 assert(s); 120 for (i=0; i<sz; i++) 121 s[i] = 'a' + test_rand(26); 122 s[i] = '\\0'; 123 return s; 124} 125 126static void rand_bytes(uint8_t *p, size_t sz) 127{ 128 int i; 129 for (i=0; i<sz; i++) 130 p[i] = test_rand(256); 131} 132 133static void libxl_bitmap_rand_init(libxl_bitmap *bitmap) 134{ 135 int i; 136 bitmap->size = test_rand(16); 137 bitmap->map = calloc(bitmap->size, sizeof(*bitmap->map)); 138 assert(bitmap->map); 139 libxl_for_each_bit(i, *bitmap) { 140 if (test_rand(2)) 141 libxl_bitmap_set(bitmap, i); 142 else 143 libxl_bitmap_reset(bitmap, i); 144 } 145} 146 147static void libxl_key_value_list_rand_init(libxl_key_value_list *pkvl) 148{ 149 int i, nr_kvp = test_rand(16); 150 libxl_key_value_list kvl = calloc(nr_kvp+1, 2*sizeof(char *)); 151 assert(kvl); 152 153 for (i = 0; i<2*nr_kvp; i += 2) { 154 kvl[i] = rand_str(); 155 if (test_rand(8)) 156 kvl[i+1] = rand_str(); 157 else 158 kvl[i+1] = NULL; 159 } 160 kvl[i] = NULL; 161 kvl[i+1] = NULL; 162 *pkvl = kvl; 163} 164 165static void libxl_cpuid_policy_list_rand_init(libxl_cpuid_policy_list *pp) 166{ 167 int i, nr_policies = test_rand(16); 168 struct { 169 const char *n; 170 int w; 171 } options[] = { 172 /* A random selection from libxl_cpuid_parse_config */ 173 {"maxleaf", 32}, 174 {"family", 8}, 175 {"model", 8}, 176 {"stepping", 4}, 177 {"localapicid", 8}, 178 {"proccount", 8}, 179 {"clflush", 8}, 180 {"brandid", 8}, 181 {"f16c", 1}, 182 {"avx", 1}, 183 {"osxsave", 1}, 184 {"xsave", 1}, 185 {"aes", 1}, 186 {"popcnt", 1}, 187 {"movbe", 1}, 188 {"x2apic", 1}, 189 {"sse4.2", 1}, 190 {"sse4.1", 1}, 191 {"dca", 1}, 192 {"pdcm", 1}, 193 {"procpkg", 6}, 194 }; 195 const int nr_options = sizeof(options)/sizeof(options[0]); 196 char buf[64]; 197 libxl_cpuid_policy_list p = NULL; 198 199 for (i = 0; i < nr_policies; i++) { 200 int opt = test_rand(nr_options); 201 int val = test_rand(1<<options[opt].w); 202 snprintf(buf, 64, \"%s=%#x\", options[opt].n, val); 203 libxl_cpuid_parse_config(&p, buf); 204 } 205 *pp = p; 206} 207 208static void libxl_string_list_rand_init(libxl_string_list *p) 209{ 210 int i, nr = test_rand(16); 211 libxl_string_list l = calloc(nr+1, sizeof(char *)); 212 assert(l); 213 214 for (i = 0; i<nr; i++) { 215 l[i] = rand_str(); 216 } 217 l[i] = NULL; 218 *p = l; 219} 220""") 221 for ty in builtins + types: 222 if isinstance(ty, idl.Number): continue 223 if ty.typename not in handcoded: 224 f.write("static void %s_rand_init(%s);\n" % \ 225 (ty.typename, 226 ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) 227 f.write("static void %s_rand_init(%s)\n" % \ 228 (ty.typename, 229 ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) 230 f.write("{\n") 231 f.write(gen_rand_init(ty, "p")) 232 f.write("}\n") 233 f.write("\n") 234 ty.rand_init = "%s_rand_init" % ty.typename 235 236 f.write(""" 237int main(int argc, char **argv) 238{ 239""") 240 241 for ty in types: 242 f.write(" %s %s_val, %s_val_new;\n" % \ 243 (ty.typename, ty.typename, ty.typename)) 244 f.write(""" 245 int rc; 246 char *s, *new_s, *json_string; 247 xentoollog_logger_stdiostream *logger; 248 libxl_ctx *ctx; 249 250 logger = xtl_createlogger_stdiostream(stderr, XTL_DETAIL, 0); 251 if (!logger) exit(1); 252 253 if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) { 254 fprintf(stderr, "cannot init xl context\\n"); 255 exit(1); 256 } 257""") 258 f.write(" printf(\"Testing TYPE_to/from_json()\\n\");\n") 259 f.write(" printf(\"----------------------\\n\");\n") 260 f.write(" printf(\"\\n\");\n") 261 for ty in [t for t in types if t.json_gen_fn is not None]: 262 arg = ty.typename + "_val" 263 f.write(" %s_rand_init(%s);\n" % (ty.typename, \ 264 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 265 if not isinstance(ty, idl.Enumeration): 266 iters = random.randrange(1,10) 267 while iters > 0: 268 f.write(" %s_init(%s_new);\n" % (ty.typename, \ 269 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 270 iters -= 1 271 f.write(" s = %s_to_json(ctx, %s);\n" % \ 272 (ty.typename, ty.pass_arg(arg, isref=False))) 273 f.write(" printf(\"%%s: %%s\\n\", \"%s\", s);\n" % ty.typename) 274 f.write(" if (s == NULL) abort();\n") 275 f.write(" rc = %s_from_json(ctx, &%s_val_new, s);\n" % \ 276 (ty.typename, ty.typename)) 277 f.write(" if (rc) abort();\n") 278 f.write(" new_s = %s_to_json(ctx, %s_new);\n" % \ 279 (ty.typename, ty.pass_arg(arg, isref=False))) 280 f.write(" if (new_s == NULL) abort();\n") 281 f.write(" if (strcmp(s, new_s)) {\n") 282 f.write(" printf(\"Huh? Regenerated string different from original string.\\n\");\n") 283 f.write(" printf(\"Regenerated string: %s\\n\", new_s);\n") 284 f.write(" abort();\n") 285 f.write(" }\n") 286 f.write(" free(s);\n") 287 f.write(" free(new_s);\n") 288 if ty.dispose_fn is not None: 289 iters = random.randrange(1,10) 290 f.write(" %s(&%s_val);\n" % (ty.dispose_fn, ty.typename)) 291 while iters > 0: 292 f.write(" %s(&%s_val_new);\n" % (ty.dispose_fn, ty.typename)) 293 iters -= 1 294 f.write("\n") 295 296 f.write(" printf(\"Testing TYPE_copy()\\n\");\n") 297 f.write(" printf(\"----------------------\\n\");\n") 298 f.write(" printf(\"\\n\");\n") 299 for ty in [t for t in types if t.copy_fn is not None]: 300 f.write(" printf(\"Testing %s_copy, \");\n" % ty.typename) 301 arg = ty.typename + "_val" 302 f.write(" %s_init(%s);\n" % (ty.typename, \ 303 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 304 f.write(" %s_rand_init(%s);\n" % (ty.typename, \ 305 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 306 f.write(" %s_init(%s_new);\n" % (ty.typename, \ 307 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 308 f.write(" %s_copy(ctx, %s_new, %s);\n" % (ty.typename, \ 309 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE), \ 310 ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) 311 f.write(" s = %s_to_json(ctx, %s);\n" % \ 312 (ty.typename, ty.pass_arg(arg, isref=False))) 313 f.write(" if (s == NULL) abort();\n") 314 f.write(" new_s = %s_to_json(ctx, %s_new);\n" % \ 315 (ty.typename, ty.pass_arg(arg, isref=False))) 316 f.write(" if (new_s == NULL) abort();\n") 317 f.write(" if (strcmp(s, new_s)) {\n") 318 f.write(" printf(\"Huh? Deep copy for %s failed. Regenerated string different from original string.\\n\");\n" \ 319 % ty.typename) 320 f.write(" printf(\"Original string: %s\\n\", s);\n") 321 f.write(" printf(\"Regenerated string: %s\\n\", new_s);\n") 322 f.write(" abort();\n") 323 f.write(" }\n") 324 f.write(" free(s);\n") 325 f.write(" free(new_s);\n") 326 if ty.dispose_fn is not None: 327 f.write(" %s(&%s_val);\n" % (ty.dispose_fn, ty.typename)) 328 f.write(" %s(&%s_val_new);\n" % (ty.dispose_fn, ty.typename)) 329 f.write(" printf(\"done\\n\");\n") 330 f.write("\n") 331 332 f.write(" printf(\"\\n\");\n") 333 f.write(" printf(\"Testing Enumerations\\n\");\n") 334 f.write(" printf(\"--------------------\\n\");\n") 335 f.write(" printf(\"\\n\");\n") 336 for ty in [t for t in types if isinstance(t,idl.Enumeration)]: 337 f.write(" printf(\"%s -- to string:\\n\");\n" % (ty.typename)) 338 for v in ty.values: 339 f.write(" printf(\"\\t%s = %%d = \\\"%%s\\\"\\n\", " \ 340 "%s, %s_to_string(%s));\n" % \ 341 (v.valuename, v.name, ty.typename, v.name)) 342 f.write("\n") 343 344 f.write(" printf(\"%s -- to JSON:\\n\");\n" % (ty.typename)) 345 for v in ty.values: 346 f.write(" json_string = %s_to_json(ctx, %s);\n" % \ 347 (ty.typename, v.name)) 348 f.write(" printf(\"\\t%s = %%d = %%s\", " \ 349 "%s, json_string);\n" %\ 350 (v.valuename, v.name)) 351 f.write(" free(json_string);\n"); 352 f.write(" json_string = NULL;\n"); 353 f.write("\n") 354 355 f.write(" printf(\"%s -- from string:\\n\");\n" % (ty.typename)) 356 for v in [v.valuename for v in ty.values] + ["AN INVALID VALUE"]: 357 n = randomize_case(v) 358 f.write(" %s_val = -1;\n" % (ty.typename)) 359 f.write(" rc = %s_from_string(\"%s\", &%s_val);\n" %\ 360 (ty.typename, n, ty.typename)) 361 362 f.write(" printf(\"\\t%s = \\\"%%s\\\" = %%d (rc %%d)\\n\", " \ 363 "\"%s\", %s_val, rc);\n" %\ 364 (v, n, ty.typename)) 365 f.write("\n") 366 367 f.write(""" 368 369 libxl_ctx_free(ctx); 370 xtl_logger_destroy((xentoollog_logger*)logger); 371 372 return 0; 373} 374""") 375