1#!/usr/bin/env python3 2import sys 3import time 4import os 5try: 6 # Python 2 7 from StringIO import StringIO 8except ImportError: 9 # Python 3 10 from io import StringIO 11sys.path.insert(0, "python") 12import libxml2 13 14# Memory debug specific 15libxml2.debugMemory(1) 16debug = 0 17verbose = 0 18quiet = 1 19 20# 21# the testsuite description 22# 23CONF=os.path.join(os.path.dirname(__file__), "test/xsdtest/xsdtestsuite.xml") 24LOG="check-xsddata-test-suite.log" 25 26log = open(LOG, "w") 27nb_schemas_tests = 0 28nb_schemas_success = 0 29nb_schemas_failed = 0 30nb_instances_tests = 0 31nb_instances_success = 0 32nb_instances_failed = 0 33 34libxml2.lineNumbersDefault(1) 35# 36# Error and warnng callbacks 37# 38def callback(ctx, str): 39 global log 40 log.write("%s%s" % (ctx, str)) 41 42libxml2.registerErrorHandler(callback, "") 43 44# 45# Resolver callback 46# 47resources = {} 48def resolver(URL, ID, ctxt): 49 global resources 50 51 if URL in resources: 52 return(StringIO(resources[URL])) 53 log.write("Resolver failure: asked %s\n" % (URL)) 54 log.write("resources: %s\n" % (resources)) 55 return None 56 57# 58# handle a valid instance 59# 60def handle_valid(node, schema): 61 global log 62 global nb_instances_success 63 global nb_instances_failed 64 65 instance = node.prop("dtd") 66 if instance is None: 67 instance = "" 68 child = node.children 69 while child != None: 70 if child.type != 'text': 71 instance = instance + child.serialize() 72 child = child.next 73 74 mem = libxml2.debugMemory(1); 75 try: 76 doc = libxml2.parseDoc(instance) 77 except: 78 doc = None 79 80 if doc is None: 81 log.write("\nFailed to parse correct instance:\n-----\n") 82 log.write(instance) 83 log.write("\n-----\n") 84 nb_instances_failed = nb_instances_failed + 1 85 return 86 87 if debug: 88 print("instance line %d" % (node.lineNo())) 89 90 try: 91 ctxt = schema.relaxNGNewValidCtxt() 92 ret = doc.relaxNGValidateDoc(ctxt) 93 del ctxt 94 except: 95 ret = -1 96 97 doc.freeDoc() 98 if mem != libxml2.debugMemory(1): 99 print("validating instance %d line %d leaks" % ( 100 nb_instances_tests, node.lineNo())) 101 102 if ret != 0: 103 log.write("\nFailed to validate correct instance:\n-----\n") 104 log.write(instance) 105 log.write("\n-----\n") 106 nb_instances_failed = nb_instances_failed + 1 107 else: 108 nb_instances_success = nb_instances_success + 1 109 110# 111# handle an invalid instance 112# 113def handle_invalid(node, schema): 114 global log 115 global nb_instances_success 116 global nb_instances_failed 117 118 instance = node.prop("dtd") 119 if instance is None: 120 instance = "" 121 child = node.children 122 while child != None: 123 if child.type != 'text': 124 instance = instance + child.serialize() 125 child = child.next 126 127# mem = libxml2.debugMemory(1); 128 129 try: 130 doc = libxml2.parseDoc(instance) 131 except: 132 doc = None 133 134 if doc is None: 135 log.write("\nStrange: failed to parse incorrect instance:\n-----\n") 136 log.write(instance) 137 log.write("\n-----\n") 138 return 139 140 if debug: 141 print("instance line %d" % (node.lineNo())) 142 143 try: 144 ctxt = schema.relaxNGNewValidCtxt() 145 ret = doc.relaxNGValidateDoc(ctxt) 146 del ctxt 147 148 except: 149 ret = -1 150 151 doc.freeDoc() 152# if mem != libxml2.debugMemory(1): 153# print("validating instance %d line %d leaks" % ( 154# nb_instances_tests, node.lineNo())) 155 156 if ret == 0: 157 log.write("\nFailed to detect validation problem in instance:\n-----\n") 158 log.write(instance) 159 log.write("\n-----\n") 160 nb_instances_failed = nb_instances_failed + 1 161 else: 162 nb_instances_success = nb_instances_success + 1 163 164# 165# handle an incorrect test 166# 167def handle_correct(node): 168 global log 169 global nb_schemas_success 170 global nb_schemas_failed 171 172 schema = "" 173 child = node.children 174 while child != None: 175 if child.type != 'text': 176 schema = schema + child.serialize() 177 child = child.next 178 179 try: 180 rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema)) 181 rngs = rngp.relaxNGParse() 182 except: 183 rngs = None 184 if rngs is None: 185 log.write("\nFailed to compile correct schema:\n-----\n") 186 log.write(schema) 187 log.write("\n-----\n") 188 nb_schemas_failed = nb_schemas_failed + 1 189 else: 190 nb_schemas_success = nb_schemas_success + 1 191 return rngs 192 193def handle_incorrect(node): 194 global log 195 global nb_schemas_success 196 global nb_schemas_failed 197 198 schema = "" 199 child = node.children 200 while child != None: 201 if child.type != 'text': 202 schema = schema + child.serialize() 203 child = child.next 204 205 try: 206 rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema)) 207 rngs = rngp.relaxNGParse() 208 except: 209 rngs = None 210 if rngs != None: 211 log.write("\nFailed to detect schema error in:\n-----\n") 212 log.write(schema) 213 log.write("\n-----\n") 214 nb_schemas_failed = nb_schemas_failed + 1 215 else: 216# log.write("\nSuccess detecting schema error in:\n-----\n") 217# log.write(schema) 218# log.write("\n-----\n") 219 nb_schemas_success = nb_schemas_success + 1 220 return None 221 222# 223# resource handling: keep a dictionary of URL->string mappings 224# 225def handle_resource(node, dir): 226 global resources 227 228 try: 229 name = node.prop('name') 230 except: 231 name = None 232 233 if name is None or name == '': 234 log.write("resource has no name") 235 return; 236 237 if dir != None: 238# name = libxml2.buildURI(name, dir) 239 name = dir + '/' + name 240 241 res = "" 242 child = node.children 243 while child != None: 244 if child.type != 'text': 245 res = res + child.serialize() 246 child = child.next 247 resources[name] = res 248 249# 250# dir handling: pseudo directory resources 251# 252def handle_dir(node, dir): 253 try: 254 name = node.prop('name') 255 except: 256 name = None 257 258 if name is None or name == '': 259 log.write("resource has no name") 260 return; 261 262 if dir != None: 263# name = libxml2.buildURI(name, dir) 264 name = dir + '/' + name 265 266 dirs = node.xpathEval('dir') 267 for dir in dirs: 268 handle_dir(dir, name) 269 res = node.xpathEval('resource') 270 for r in res: 271 handle_resource(r, name) 272 273# 274# handle a testCase element 275# 276def handle_testCase(node): 277 global nb_schemas_tests 278 global nb_instances_tests 279 global resources 280 281 sections = node.xpathEval('string(section)') 282 log.write("\n ======== test %d line %d section %s ==========\n" % ( 283 284 nb_schemas_tests, node.lineNo(), sections)) 285 resources = {} 286 if debug: 287 print("test %d line %d" % (nb_schemas_tests, node.lineNo())) 288 289 dirs = node.xpathEval('dir') 290 for dir in dirs: 291 handle_dir(dir, None) 292 res = node.xpathEval('resource') 293 for r in res: 294 handle_resource(r, None) 295 296 tsts = node.xpathEval('incorrect') 297 if tsts != []: 298 if len(tsts) != 1: 299 print("warning test line %d has more than one <incorrect> example" %(node.lineNo())) 300 schema = handle_incorrect(tsts[0]) 301 else: 302 tsts = node.xpathEval('correct') 303 if tsts != []: 304 if len(tsts) != 1: 305 print("warning test line %d has more than one <correct> example"% (node.lineNo())) 306 schema = handle_correct(tsts[0]) 307 else: 308 print("warning <testCase> line %d has no <correct> nor <incorrect> child" % (node.lineNo())) 309 310 nb_schemas_tests = nb_schemas_tests + 1; 311 312 valids = node.xpathEval('valid') 313 invalids = node.xpathEval('invalid') 314 nb_instances_tests = nb_instances_tests + len(valids) + len(invalids) 315 if schema != None: 316 for valid in valids: 317 handle_valid(valid, schema) 318 for invalid in invalids: 319 handle_invalid(invalid, schema) 320 321 322# 323# handle a testSuite element 324# 325def handle_testSuite(node, level = 0): 326 global nb_schemas_tests, nb_schemas_success, nb_schemas_failed 327 global nb_instances_tests, nb_instances_success, nb_instances_failed 328 if verbose and level >= 0: 329 old_schemas_tests = nb_schemas_tests 330 old_schemas_success = nb_schemas_success 331 old_schemas_failed = nb_schemas_failed 332 old_instances_tests = nb_instances_tests 333 old_instances_success = nb_instances_success 334 old_instances_failed = nb_instances_failed 335 336 docs = node.xpathEval('documentation') 337 authors = node.xpathEval('author') 338 if docs != []: 339 msg = "" 340 for doc in docs: 341 msg = msg + doc.content + " " 342 if authors != []: 343 msg = msg + "written by " 344 for author in authors: 345 msg = msg + author.content + " " 346 if quiet == 0: 347 print(msg) 348 sections = node.xpathEval('section') 349 if verbose and sections != [] and level <= 0: 350 msg = "" 351 for section in sections: 352 msg = msg + section.content + " " 353 if quiet == 0: 354 print("Tests for section %s" % (msg)) 355 for test in node.xpathEval('testCase'): 356 handle_testCase(test) 357 for test in node.xpathEval('testSuite'): 358 handle_testSuite(test, level + 1) 359 360 361 if verbose and level >= 0 : 362 if sections != []: 363 msg = "" 364 for section in sections: 365 msg = msg + section.content + " " 366 print("Result of tests for section %s" % (msg)) 367 elif docs != []: 368 msg = "" 369 for doc in docs: 370 msg = msg + doc.content + " " 371 print("Result of tests for %s" % (msg)) 372 373 if nb_schemas_tests != old_schemas_tests: 374 print("found %d test schemas: %d success %d failures" % ( 375 nb_schemas_tests - old_schemas_tests, 376 nb_schemas_success - old_schemas_success, 377 nb_schemas_failed - old_schemas_failed)) 378 if nb_instances_tests != old_instances_tests: 379 print("found %d test instances: %d success %d failures" % ( 380 nb_instances_tests - old_instances_tests, 381 nb_instances_success - old_instances_success, 382 nb_instances_failed - old_instances_failed)) 383# 384# Parse the conf file 385# 386libxml2.substituteEntitiesDefault(1); 387testsuite = libxml2.parseFile(CONF) 388 389# 390# Error and warnng callbacks 391# 392def callback(ctx, str): 393 global log 394 log.write("%s%s" % (ctx, str)) 395 396libxml2.registerErrorHandler(callback, "") 397 398libxml2.setEntityLoader(resolver) 399root = testsuite.getRootElement() 400if root.name != 'testSuite': 401 print("%s doesn't start with a testSuite element, aborting" % (CONF)) 402 sys.exit(1) 403if quiet == 0: 404 print("Running Relax NG testsuite") 405handle_testSuite(root) 406 407if quiet == 0 or nb_schemas_failed != 0: 408 print("\nTOTAL:\nfound %d test schemas: %d success %d failures" % ( 409 nb_schemas_tests, nb_schemas_success, nb_schemas_failed)) 410if quiet == 0 or nb_instances_failed != 0: 411 print("found %d test instances: %d success %d failures" % ( 412 nb_instances_tests, nb_instances_success, nb_instances_failed)) 413 414testsuite.freeDoc() 415 416# Memory debug specific 417libxml2.relaxNGCleanupTypes() 418libxml2.cleanupParser() 419if libxml2.debugMemory(1) == 0: 420 if quiet == 0: 421 print("OK") 422else: 423 print("Memory leak %d bytes" % (libxml2.debugMemory(1))) 424 libxml2.dumpMemory() 425