blob: 3e1521237c861eeaca3bc502f4c57ffa596c3756 [file] [log] [blame]
Ross Burton4762c852022-12-06 21:40:01 +00001#!/usr/bin/env python3
Daniel Veillard1703c5f2003-02-10 14:28:44 +00002import sys
3import time
4import os
Nick Wellnhofer649ddb42022-03-29 15:55:51 +02005try:
6 # Python 2
7 from StringIO import StringIO
8except ImportError:
9 # Python 3
10 from io import StringIO
William M. Brackcb40c222004-10-02 22:55:49 +000011sys.path.insert(0, "python")
Daniel Veillard1703c5f2003-02-10 14:28:44 +000012import libxml2
13
Daniel Veillard3ebc7d42003-02-24 17:17:58 +000014# Memory debug specific
15libxml2.debugMemory(1)
Daniel Veillardd4310742003-02-18 21:12:46 +000016debug = 0
Daniel Veillarda1a9d042003-03-18 16:53:17 +000017verbose = 0
Daniel Veillard6dc91962004-03-22 19:10:02 +000018quiet = 1
Daniel Veillardd4310742003-02-18 21:12:46 +000019
Daniel Veillard1703c5f2003-02-10 14:28:44 +000020#
21# the testsuite description
22#
Daniel Veillard9ebb6322008-01-11 07:19:24 +000023CONF=os.path.join(os.path.dirname(__file__), "test/relaxng/OASIS/spectest.xml")
Daniel Veillard1703c5f2003-02-10 14:28:44 +000024LOG="check-relaxng-test-suite.log"
Daniel Veillard416589a2003-02-17 17:25:42 +000025RES="relaxng-test-results.xml"
26
Daniel Veillard1703c5f2003-02-10 14:28:44 +000027log = open(LOG, "w")
28nb_schemas_tests = 0
29nb_schemas_success = 0
30nb_schemas_failed = 0
31nb_instances_tests = 0
32nb_instances_success = 0
33nb_instances_failed = 0
34
35libxml2.lineNumbersDefault(1)
36#
37# Error and warnng callbacks
38#
39def callback(ctx, str):
40 global log
41 log.write("%s%s" % (ctx, str))
42
43libxml2.registerErrorHandler(callback, "")
44
45#
46# Resolver callback
47#
48resources = {}
49def resolver(URL, ID, ctxt):
50 global resources
51
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020052 if URL.find('#') != -1:
53 URL = URL[0:URL.find('#')]
54 if URL in resources:
55 return(StringIO(resources[URL]))
Daniel Veillard1703c5f2003-02-10 14:28:44 +000056 log.write("Resolver failure: asked %s\n" % (URL))
57 log.write("resources: %s\n" % (resources))
58 return None
59
Daniel Veillard416589a2003-02-17 17:25:42 +000060#
61# Load the previous results
62#
63#results = {}
64#previous = {}
65#
66#try:
67# res = libxml2.parseFile(RES)
68#except:
69# log.write("Could not parse %s" % (RES))
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020070
Daniel Veillard1703c5f2003-02-10 14:28:44 +000071#
72# handle a valid instance
73#
74def handle_valid(node, schema):
75 global log
76 global nb_instances_success
77 global nb_instances_failed
78
79 instance = ""
80 child = node.children
81 while child != None:
82 if child.type != 'text':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020083 instance = instance + child.serialize()
84 child = child.next
Daniel Veillard1703c5f2003-02-10 14:28:44 +000085
86 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020087 doc = libxml2.parseDoc(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +000088 except:
89 doc = None
90
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020091 if doc is None:
Daniel Veillard1703c5f2003-02-10 14:28:44 +000092 log.write("\nFailed to parse correct instance:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020093 log.write(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +000094 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +020095 nb_instances_failed = nb_instances_failed + 1
96 return
Daniel Veillard1703c5f2003-02-10 14:28:44 +000097
98 try:
99 ctxt = schema.relaxNGNewValidCtxt()
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200100 ret = doc.relaxNGValidateDoc(ctxt)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000101 except:
102 ret = -1
103 if ret != 0:
104 log.write("\nFailed to validate correct instance:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200105 log.write(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000106 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200107 nb_instances_failed = nb_instances_failed + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000108 else:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200109 nb_instances_success = nb_instances_success + 1
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000110 doc.freeDoc()
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000111
112#
113# handle an invalid instance
114#
115def handle_invalid(node, schema):
116 global log
117 global nb_instances_success
118 global nb_instances_failed
119
120 instance = ""
121 child = node.children
122 while child != None:
123 if child.type != 'text':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200124 instance = instance + child.serialize()
125 child = child.next
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000126
127 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200128 doc = libxml2.parseDoc(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000129 except:
130 doc = None
131
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200132 if doc is None:
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000133 log.write("\nStrange: failed to parse incorrect instance:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200134 log.write(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000135 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200136 return
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000137
138 try:
139 ctxt = schema.relaxNGNewValidCtxt()
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200140 ret = doc.relaxNGValidateDoc(ctxt)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000141 except:
142 ret = -1
143 if ret == 0:
144 log.write("\nFailed to detect validation problem in instance:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200145 log.write(instance)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000146 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200147 nb_instances_failed = nb_instances_failed + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000148 else:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200149 nb_instances_success = nb_instances_success + 1
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000150 doc.freeDoc()
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000151
152#
153# handle an incorrect test
154#
155def handle_correct(node):
156 global log
157 global nb_schemas_success
158 global nb_schemas_failed
159
160 schema = ""
161 child = node.children
162 while child != None:
163 if child.type != 'text':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200164 schema = schema + child.serialize()
165 child = child.next
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000166
167 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200168 rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
169 rngs = rngp.relaxNGParse()
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000170 except:
171 rngs = None
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200172 if rngs is None:
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000173 log.write("\nFailed to compile correct schema:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200174 log.write(schema)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000175 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200176 nb_schemas_failed = nb_schemas_failed + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000177 else:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200178 nb_schemas_success = nb_schemas_success + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000179 return rngs
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200180
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000181def handle_incorrect(node):
182 global log
183 global nb_schemas_success
184 global nb_schemas_failed
185
186 schema = ""
187 child = node.children
188 while child != None:
189 if child.type != 'text':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200190 schema = schema + child.serialize()
191 child = child.next
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000192
193 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200194 rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
195 rngs = rngp.relaxNGParse()
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000196 except:
197 rngs = None
198 if rngs != None:
199 log.write("\nFailed to detect schema error in:\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200200 log.write(schema)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000201 log.write("\n-----\n")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200202 nb_schemas_failed = nb_schemas_failed + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000203 else:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200204# log.write("\nSuccess detecting schema error in:\n-----\n")
205# log.write(schema)
206# log.write("\n-----\n")
207 nb_schemas_success = nb_schemas_success + 1
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000208 return None
209
210#
211# resource handling: keep a dictionary of URL->string mappings
212#
213def handle_resource(node, dir):
214 global resources
215
216 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200217 name = node.prop('name')
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000218 except:
219 name = None
220
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200221 if name is None or name == '':
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000222 log.write("resource has no name")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200223 return;
224
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000225 if dir != None:
226# name = libxml2.buildURI(name, dir)
227 name = dir + '/' + name
228
229 res = ""
230 child = node.children
231 while child != None:
232 if child.type != 'text':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200233 res = res + child.serialize()
234 child = child.next
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000235 resources[name] = res
236
237#
238# dir handling: pseudo directory resources
239#
240def handle_dir(node, dir):
241 try:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200242 name = node.prop('name')
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000243 except:
244 name = None
245
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200246 if name is None or name == '':
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000247 log.write("resource has no name")
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200248 return;
249
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000250 if dir != None:
251# name = libxml2.buildURI(name, dir)
252 name = dir + '/' + name
253
254 dirs = node.xpathEval('dir')
255 for dir in dirs:
256 handle_dir(dir, name)
257 res = node.xpathEval('resource')
258 for r in res:
259 handle_resource(r, name)
260
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000261#
262# handle a testCase element
263#
264def handle_testCase(node):
265 global nb_schemas_tests
266 global nb_instances_tests
267 global resources
268
Daniel Veillard77648bb2003-02-20 15:03:22 +0000269 sections = node.xpathEval('string(section)')
270 log.write("\n ======== test %d line %d section %s ==========\n" % (
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000271
Daniel Veillard77648bb2003-02-20 15:03:22 +0000272 nb_schemas_tests, node.lineNo(), sections))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000273 resources = {}
Daniel Veillardd4310742003-02-18 21:12:46 +0000274 if debug:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200275 print("test %d line %d" % (nb_schemas_tests, node.lineNo()))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000276
277 dirs = node.xpathEval('dir')
278 for dir in dirs:
279 handle_dir(dir, None)
280 res = node.xpathEval('resource')
281 for r in res:
282 handle_resource(r, None)
283
284 tsts = node.xpathEval('incorrect')
285 if tsts != []:
286 if len(tsts) != 1:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200287 print("warning test line %d has more than one <incorrect> example" %(node.lineNo()))
288 schema = handle_incorrect(tsts[0])
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000289 else:
290 tsts = node.xpathEval('correct')
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200291 if tsts != []:
292 if len(tsts) != 1:
293 print("warning test line %d has more than one <correct> example"% (node.lineNo()))
294 schema = handle_correct(tsts[0])
295 else:
296 print("warning <testCase> line %d has no <correct> nor <incorrect> child" % (node.lineNo()))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000297
298 nb_schemas_tests = nb_schemas_tests + 1;
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200299
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000300 valids = node.xpathEval('valid')
301 invalids = node.xpathEval('invalid')
302 nb_instances_tests = nb_instances_tests + len(valids) + len(invalids)
303 if schema != None:
304 for valid in valids:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200305 handle_valid(valid, schema)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000306 for invalid in invalids:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200307 handle_invalid(invalid, schema)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000308
309
310#
311# handle a testSuite element
312#
Daniel Veillardd2298792003-02-14 16:54:11 +0000313def handle_testSuite(node, level = 0):
314 global nb_schemas_tests, nb_schemas_success, nb_schemas_failed
315 global nb_instances_tests, nb_instances_success, nb_instances_failed
Daniel Veillard6dc91962004-03-22 19:10:02 +0000316 global quiet
Daniel Veillardd2298792003-02-14 16:54:11 +0000317 if level >= 1:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200318 old_schemas_tests = nb_schemas_tests
319 old_schemas_success = nb_schemas_success
320 old_schemas_failed = nb_schemas_failed
321 old_instances_tests = nb_instances_tests
322 old_instances_success = nb_instances_success
323 old_instances_failed = nb_instances_failed
Daniel Veillardd2298792003-02-14 16:54:11 +0000324
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000325 docs = node.xpathEval('documentation')
326 authors = node.xpathEval('author')
327 if docs != []:
328 msg = ""
329 for doc in docs:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200330 msg = msg + doc.content + " "
331 if authors != []:
332 msg = msg + "written by "
333 for author in authors:
334 msg = msg + author.content + " "
335 if quiet == 0:
336 print(msg)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000337 sections = node.xpathEval('section')
Daniel Veillard77648bb2003-02-20 15:03:22 +0000338 if sections != [] and level <= 0:
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000339 msg = ""
340 for section in sections:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200341 msg = msg + section.content + " "
342 if quiet == 0:
343 print("Tests for section %s" % (msg))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000344 for test in node.xpathEval('testCase'):
345 handle_testCase(test)
346 for test in node.xpathEval('testSuite'):
Daniel Veillardd2298792003-02-14 16:54:11 +0000347 handle_testSuite(test, level + 1)
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200348
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000349
Daniel Veillarda1a9d042003-03-18 16:53:17 +0000350 if verbose and level >= 1 and sections != []:
Daniel Veillard77648bb2003-02-20 15:03:22 +0000351 msg = ""
352 for section in sections:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200353 msg = msg + section.content + " "
354 print("Result of tests for section %s" % (msg))
Daniel Veillardd2298792003-02-14 16:54:11 +0000355 if nb_schemas_tests != old_schemas_tests:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200356 print("found %d test schemas: %d success %d failures" % (
357 nb_schemas_tests - old_schemas_tests,
358 nb_schemas_success - old_schemas_success,
359 nb_schemas_failed - old_schemas_failed))
360 if nb_instances_tests != old_instances_tests:
361 print("found %d test instances: %d success %d failures" % (
362 nb_instances_tests - old_instances_tests,
363 nb_instances_success - old_instances_success,
364 nb_instances_failed - old_instances_failed))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000365#
366# Parse the conf file
367#
Daniel Veillardd2298792003-02-14 16:54:11 +0000368libxml2.substituteEntitiesDefault(1);
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000369testsuite = libxml2.parseFile(CONF)
Daniel Veillardd2298792003-02-14 16:54:11 +0000370libxml2.setEntityLoader(resolver)
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000371root = testsuite.getRootElement()
372if root.name != 'testSuite':
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200373 print("%s doesn't start with a testSuite element, aborting" % (CONF))
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000374 sys.exit(1)
Daniel Veillard6dc91962004-03-22 19:10:02 +0000375if quiet == 0:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200376 print("Running Relax NG testsuite")
Daniel Veillard1703c5f2003-02-10 14:28:44 +0000377handle_testSuite(root)
378
Daniel Veillard6dc91962004-03-22 19:10:02 +0000379if quiet == 0:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200380 print("\nTOTAL:\n")
Daniel Veillard6dc91962004-03-22 19:10:02 +0000381if quiet == 0 or nb_schemas_failed != 0:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200382 print("found %d test schemas: %d success %d failures" % (
383 nb_schemas_tests, nb_schemas_success, nb_schemas_failed))
Daniel Veillard6dc91962004-03-22 19:10:02 +0000384if quiet == 0 or nb_instances_failed != 0:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200385 print("found %d test instances: %d success %d failures" % (
386 nb_instances_tests, nb_instances_success, nb_instances_failed))
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000387
388testsuite.freeDoc()
389
390# Memory debug specific
391libxml2.relaxNGCleanupTypes()
392libxml2.cleanupParser()
393if libxml2.debugMemory(1) == 0:
Daniel Veillard6dc91962004-03-22 19:10:02 +0000394 if quiet == 0:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200395 print("OK")
Daniel Veillard3ebc7d42003-02-24 17:17:58 +0000396else:
Nick Wellnhofer649ddb42022-03-29 15:55:51 +0200397 print("Memory leak %d bytes" % (libxml2.debugMemory(1)))