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