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