mirror of
https://gitlab.gnome.org/GNOME/libxml2.git
synced 2024-12-24 21:33:51 +03:00
4762c85668
As per https://peps.python.org/pep-0394/, the python binary can be one of the following options: - Python 2 - Python 3 - Not exist All of the scripts in libxml2 use 'python', which may not exist. As Python 2 reached EOL on the 1st January 2020, it's safe to move the scripts to use python3 explicitly.
423 lines
11 KiB
Python
Executable File
423 lines
11 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import sys
|
|
import time
|
|
import os
|
|
try:
|
|
# Python 2
|
|
from StringIO import StringIO
|
|
except ImportError:
|
|
# Python 3
|
|
from io import StringIO
|
|
sys.path.insert(0, "python")
|
|
import libxml2
|
|
|
|
# Memory debug specific
|
|
libxml2.debugMemory(1)
|
|
debug = 0
|
|
quiet = 1
|
|
|
|
#
|
|
# the testsuite description
|
|
#
|
|
CONF=os.path.join(os.path.dirname(__file__), "test/relaxng/testsuite.xml")
|
|
LOG="check-relaxng-test-suite2.log"
|
|
|
|
log = open(LOG, "w")
|
|
nb_schemas_tests = 0
|
|
nb_schemas_success = 0
|
|
nb_schemas_failed = 0
|
|
nb_instances_tests = 0
|
|
nb_instances_success = 0
|
|
nb_instances_failed = 0
|
|
|
|
libxml2.lineNumbersDefault(1)
|
|
#
|
|
# Resolver callback
|
|
#
|
|
resources = {}
|
|
def resolver(URL, ID, ctxt):
|
|
global resources
|
|
|
|
if URL in resources:
|
|
return(StringIO(resources[URL]))
|
|
log.write("Resolver failure: asked %s\n" % (URL))
|
|
log.write("resources: %s\n" % (resources))
|
|
return None
|
|
|
|
#
|
|
# Load the previous results
|
|
#
|
|
#results = {}
|
|
#previous = {}
|
|
#
|
|
#try:
|
|
# res = libxml2.parseFile(RES)
|
|
#except:
|
|
# log.write("Could not parse %s" % (RES))
|
|
|
|
#
|
|
# handle a valid instance
|
|
#
|
|
def handle_valid(node, schema):
|
|
global log
|
|
global nb_instances_success
|
|
global nb_instances_failed
|
|
|
|
instance = node.prop("dtd")
|
|
if instance is None:
|
|
instance = ""
|
|
child = node.children
|
|
while child != None:
|
|
if child.type != 'text':
|
|
instance = instance + child.serialize()
|
|
child = child.next
|
|
|
|
# mem = libxml2.debugMemory(1);
|
|
try:
|
|
doc = libxml2.parseDoc(instance)
|
|
except:
|
|
doc = None
|
|
|
|
if doc is None:
|
|
log.write("\nFailed to parse correct instance:\n-----\n")
|
|
log.write(instance)
|
|
log.write("\n-----\n")
|
|
nb_instances_failed = nb_instances_failed + 1
|
|
return
|
|
|
|
if debug:
|
|
print("instance line %d" % (node.lineNo()))
|
|
|
|
try:
|
|
ctxt = schema.relaxNGNewValidCtxt()
|
|
ret = doc.relaxNGValidateDoc(ctxt)
|
|
del ctxt
|
|
except:
|
|
ret = -1
|
|
|
|
doc.freeDoc()
|
|
# if mem != libxml2.debugMemory(1):
|
|
# print("validating instance %d line %d leaks" % (
|
|
# nb_instances_tests, node.lineNo()))
|
|
|
|
if ret != 0:
|
|
log.write("\nFailed to validate correct instance:\n-----\n")
|
|
log.write(instance)
|
|
log.write("\n-----\n")
|
|
nb_instances_failed = nb_instances_failed + 1
|
|
else:
|
|
nb_instances_success = nb_instances_success + 1
|
|
|
|
#
|
|
# handle an invalid instance
|
|
#
|
|
def handle_invalid(node, schema):
|
|
global log
|
|
global nb_instances_success
|
|
global nb_instances_failed
|
|
|
|
instance = node.prop("dtd")
|
|
if instance is None:
|
|
instance = ""
|
|
child = node.children
|
|
while child != None:
|
|
if child.type != 'text':
|
|
instance = instance + child.serialize()
|
|
child = child.next
|
|
|
|
# mem = libxml2.debugMemory(1);
|
|
|
|
try:
|
|
doc = libxml2.parseDoc(instance)
|
|
except:
|
|
doc = None
|
|
|
|
if doc is None:
|
|
log.write("\nStrange: failed to parse incorrect instance:\n-----\n")
|
|
log.write(instance)
|
|
log.write("\n-----\n")
|
|
return
|
|
|
|
if debug:
|
|
print("instance line %d" % (node.lineNo()))
|
|
|
|
try:
|
|
ctxt = schema.relaxNGNewValidCtxt()
|
|
ret = doc.relaxNGValidateDoc(ctxt)
|
|
del ctxt
|
|
|
|
except:
|
|
ret = -1
|
|
|
|
doc.freeDoc()
|
|
# mem2 = libxml2.debugMemory(1)
|
|
# if mem != mem2:
|
|
# print("validating instance %d line %d leaks %d bytes" % (
|
|
# nb_instances_tests, node.lineNo(), mem2 - mem))
|
|
|
|
if ret == 0:
|
|
log.write("\nFailed to detect validation problem in instance:\n-----\n")
|
|
log.write(instance)
|
|
log.write("\n-----\n")
|
|
nb_instances_failed = nb_instances_failed + 1
|
|
else:
|
|
nb_instances_success = nb_instances_success + 1
|
|
|
|
#
|
|
# handle an incorrect test
|
|
#
|
|
def handle_correct(node):
|
|
global log
|
|
global nb_schemas_success
|
|
global nb_schemas_failed
|
|
|
|
schema = ""
|
|
child = node.children
|
|
while child != None:
|
|
if child.type != 'text':
|
|
schema = schema + child.serialize()
|
|
child = child.next
|
|
|
|
try:
|
|
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
|
|
rngs = rngp.relaxNGParse()
|
|
except:
|
|
rngs = None
|
|
if rngs is None:
|
|
log.write("\nFailed to compile correct schema:\n-----\n")
|
|
log.write(schema)
|
|
log.write("\n-----\n")
|
|
nb_schemas_failed = nb_schemas_failed + 1
|
|
else:
|
|
nb_schemas_success = nb_schemas_success + 1
|
|
return rngs
|
|
|
|
def handle_incorrect(node):
|
|
global log
|
|
global nb_schemas_success
|
|
global nb_schemas_failed
|
|
|
|
schema = ""
|
|
child = node.children
|
|
while child != None:
|
|
if child.type != 'text':
|
|
schema = schema + child.serialize()
|
|
child = child.next
|
|
|
|
try:
|
|
rngp = libxml2.relaxNGNewMemParserCtxt(schema, len(schema))
|
|
rngs = rngp.relaxNGParse()
|
|
except:
|
|
rngs = None
|
|
if rngs != None:
|
|
log.write("\nFailed to detect schema error in:\n-----\n")
|
|
log.write(schema)
|
|
log.write("\n-----\n")
|
|
nb_schemas_failed = nb_schemas_failed + 1
|
|
else:
|
|
# log.write("\nSuccess detecting schema error in:\n-----\n")
|
|
# log.write(schema)
|
|
# log.write("\n-----\n")
|
|
nb_schemas_success = nb_schemas_success + 1
|
|
return None
|
|
|
|
#
|
|
# resource handling: keep a dictionary of URL->string mappings
|
|
#
|
|
def handle_resource(node, dir):
|
|
global resources
|
|
|
|
try:
|
|
name = node.prop('name')
|
|
except:
|
|
name = None
|
|
|
|
if name is None or name == '':
|
|
log.write("resource has no name")
|
|
return;
|
|
|
|
if dir != None:
|
|
# name = libxml2.buildURI(name, dir)
|
|
name = dir + '/' + name
|
|
|
|
res = ""
|
|
child = node.children
|
|
while child != None:
|
|
if child.type != 'text':
|
|
res = res + child.serialize()
|
|
child = child.next
|
|
resources[name] = res
|
|
|
|
#
|
|
# dir handling: pseudo directory resources
|
|
#
|
|
def handle_dir(node, dir):
|
|
try:
|
|
name = node.prop('name')
|
|
except:
|
|
name = None
|
|
|
|
if name is None or name == '':
|
|
log.write("resource has no name")
|
|
return;
|
|
|
|
if dir != None:
|
|
# name = libxml2.buildURI(name, dir)
|
|
name = dir + '/' + name
|
|
|
|
dirs = node.xpathEval('dir')
|
|
for dir in dirs:
|
|
handle_dir(dir, name)
|
|
res = node.xpathEval('resource')
|
|
for r in res:
|
|
handle_resource(r, name)
|
|
|
|
#
|
|
# handle a testCase element
|
|
#
|
|
def handle_testCase(node):
|
|
global nb_schemas_tests
|
|
global nb_instances_tests
|
|
global resources
|
|
|
|
sections = node.xpathEval('string(section)')
|
|
log.write("\n ======== test %d line %d section %s ==========\n" % (
|
|
|
|
nb_schemas_tests, node.lineNo(), sections))
|
|
resources = {}
|
|
if debug:
|
|
print("test %d line %d" % (nb_schemas_tests, node.lineNo()))
|
|
|
|
dirs = node.xpathEval('dir')
|
|
for dir in dirs:
|
|
handle_dir(dir, None)
|
|
res = node.xpathEval('resource')
|
|
for r in res:
|
|
handle_resource(r, None)
|
|
|
|
tsts = node.xpathEval('incorrect')
|
|
if tsts != []:
|
|
if len(tsts) != 1:
|
|
print("warning test line %d has more than one <incorrect> example" %(node.lineNo()))
|
|
schema = handle_incorrect(tsts[0])
|
|
else:
|
|
tsts = node.xpathEval('correct')
|
|
if tsts != []:
|
|
if len(tsts) != 1:
|
|
print("warning test line %d has more than one <correct> example"% (node.lineNo()))
|
|
schema = handle_correct(tsts[0])
|
|
else:
|
|
print("warning <testCase> line %d has no <correct> nor <incorrect> child" % (node.lineNo()))
|
|
|
|
nb_schemas_tests = nb_schemas_tests + 1;
|
|
|
|
valids = node.xpathEval('valid')
|
|
invalids = node.xpathEval('invalid')
|
|
nb_instances_tests = nb_instances_tests + len(valids) + len(invalids)
|
|
if schema != None:
|
|
for valid in valids:
|
|
handle_valid(valid, schema)
|
|
for invalid in invalids:
|
|
handle_invalid(invalid, schema)
|
|
|
|
|
|
#
|
|
# handle a testSuite element
|
|
#
|
|
def handle_testSuite(node, level = 0):
|
|
global nb_schemas_tests, nb_schemas_success, nb_schemas_failed
|
|
global nb_instances_tests, nb_instances_success, nb_instances_failed
|
|
if level >= 1:
|
|
old_schemas_tests = nb_schemas_tests
|
|
old_schemas_success = nb_schemas_success
|
|
old_schemas_failed = nb_schemas_failed
|
|
old_instances_tests = nb_instances_tests
|
|
old_instances_success = nb_instances_success
|
|
old_instances_failed = nb_instances_failed
|
|
|
|
docs = node.xpathEval('documentation')
|
|
authors = node.xpathEval('author')
|
|
if docs != []:
|
|
msg = ""
|
|
for doc in docs:
|
|
msg = msg + doc.content + " "
|
|
if authors != []:
|
|
msg = msg + "written by "
|
|
for author in authors:
|
|
msg = msg + author.content + " "
|
|
if quiet == 0:
|
|
print(msg)
|
|
sections = node.xpathEval('section')
|
|
if sections != [] and level <= 0:
|
|
msg = ""
|
|
for section in sections:
|
|
msg = msg + section.content + " "
|
|
if quiet == 0:
|
|
print("Tests for section %s" % (msg))
|
|
for test in node.xpathEval('testCase'):
|
|
handle_testCase(test)
|
|
for test in node.xpathEval('testSuite'):
|
|
handle_testSuite(test, level + 1)
|
|
|
|
|
|
if level >= 1 and sections != []:
|
|
msg = ""
|
|
for section in sections:
|
|
msg = msg + section.content + " "
|
|
print("Result of tests for section %s" % (msg))
|
|
if nb_schemas_tests != old_schemas_tests:
|
|
print("found %d test schemas: %d success %d failures" % (
|
|
nb_schemas_tests - old_schemas_tests,
|
|
nb_schemas_success - old_schemas_success,
|
|
nb_schemas_failed - old_schemas_failed))
|
|
if nb_instances_tests != old_instances_tests:
|
|
print("found %d test instances: %d success %d failures" % (
|
|
nb_instances_tests - old_instances_tests,
|
|
nb_instances_success - old_instances_success,
|
|
nb_instances_failed - old_instances_failed))
|
|
#
|
|
# Parse the conf file
|
|
#
|
|
libxml2.substituteEntitiesDefault(1);
|
|
testsuite = libxml2.parseFile(CONF)
|
|
|
|
#
|
|
# Error and warnng callbacks
|
|
#
|
|
def callback(ctx, str):
|
|
global log
|
|
log.write("%s%s" % (ctx, str))
|
|
|
|
libxml2.registerErrorHandler(callback, "")
|
|
|
|
libxml2.setEntityLoader(resolver)
|
|
root = testsuite.getRootElement()
|
|
if root.name != 'testSuite':
|
|
print("%s doesn't start with a testSuite element, aborting" % (CONF))
|
|
sys.exit(1)
|
|
if quiet == 0:
|
|
print("Running Relax NG testsuite")
|
|
handle_testSuite(root)
|
|
|
|
if quiet == 0:
|
|
print("\nTOTAL:\n")
|
|
if quiet == 0 or nb_schemas_failed != 0:
|
|
print("found %d test schemas: %d success %d failures" % (
|
|
nb_schemas_tests, nb_schemas_success, nb_schemas_failed))
|
|
if quiet == 0 or nb_instances_failed != 0:
|
|
print("found %d test instances: %d success %d failures" % (
|
|
nb_instances_tests, nb_instances_success, nb_instances_failed))
|
|
|
|
log.close()
|
|
testsuite.freeDoc()
|
|
|
|
# Memory debug specific
|
|
libxml2.relaxNGCleanupTypes()
|
|
libxml2.cleanupParser()
|
|
if libxml2.debugMemory(1) == 0:
|
|
if quiet == 0:
|
|
print("OK")
|
|
else:
|
|
print("Memory leak %d bytes" % (libxml2.debugMemory(1)))
|
|
libxml2.dumpMemory()
|