xref: /aosp_15_r20/external/cronet/third_party/libxml/src/check-relaxng-test-suite2.py (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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