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