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