From 2cdd2f3a828d819d63fac949abd67d94d2e36b97 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Mon, 6 Sep 2004 12:55:41 +0000 Subject: more cleanup in integrating the xstc testsuite Daniel * xstc/Makefile.am xstc/xstc-to-python.xsl xstc/xstc.py Makefile.am: more cleanup in integrating the xstc testsuite Daniel --- xstc/.cvsignore | 5 +- xstc/Makefile.am | 10 +- xstc/xstc-to-python.xsl | 525 +--------------------------------------------- xstc/xstc.py | 542 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 554 insertions(+), 528 deletions(-) create mode 100755 xstc/xstc.py (limited to 'xstc') diff --git a/xstc/.cvsignore b/xstc/.cvsignore index a92619b0..6858b698 100644 --- a/xstc/.cvsignore +++ b/xstc/.cvsignore @@ -2,4 +2,7 @@ XSTC-20020116.tar.gz msxsdtest nisttest suntest - +ms-test.py +nist-test.py +sun-test.py +test.log diff --git a/xstc/Makefile.am b/xstc/Makefile.am index 63038480..6509fcb0 100644 --- a/xstc/Makefile.am +++ b/xstc/Makefile.am @@ -40,13 +40,13 @@ $(TESTDIRS): pytests: $(PYSCRIPTS) $(TESTDIRS) -@(if [ -x nist-test.py -a -d nisttest ] ; then \ - echo "# Running NIST Schemas tests"; \ + echo "## Running NIST Schemas tests"; \ ./nist-test.py -s -b $(srcdir) ; fi) -@(if [ -x sun-test.py -a -d suntest ] ; then \ - echo "# Running Sun Schemas tests"; \ + echo "## Running Sun Schemas tests"; \ ./sun-test.py -s -b $(srcdir) ; fi) -@(if [ -x ms-test.py -a -d msxsdtest ] ; then \ - echo "# Running Microsoft Schemas tests"; \ + echo "## Running Microsoft Schemas tests"; \ ./ms-test.py -s -b $(srcdir) ; fi) tests: @@ -54,7 +54,7 @@ tests: $(MAKE) MAKEFLAGS+=--silent pytests ; fi); clean: - rm -f $(PYSCRIPTS) + rm -f $(PYSCRIPTS) test.log distclean: - rm -rf $(PYSCRIPTS) $(TESTDIRS) + rm -rf $(PYSCRIPTS) $(TESTDIRS) test.log diff --git a/xstc/xstc-to-python.xsl b/xstc/xstc-to-python.xsl index 3ebdeb87..31fe0389 100755 --- a/xstc/xstc-to-python.xsl +++ b/xstc/xstc-to-python.xsl @@ -5,528 +5,10 @@ #!/usr/bin/python -u # -# This is the MS subset of the W3C test suite for XML Schemas. -# This file is generated from the MS W3c test suite description file. +# This file is generated from the W3C test suite description file. # -import sys, os -import exceptions, optparse -import libxml2 - -opa = optparse.OptionParser() - -opa.add_option("-b", "--base", action="store", type="string", dest="baseDir", - default="", - help="""The base directory; i.e. the parent folder of the - "nisttest", "suntest" and "msxsdtest" directories.""") - -opa.add_option("-o", "--out", action="store", type="string", dest="logFile", - default="test.log", - help="The filepath of the log file to be created") - -opa.add_option("--no-log", action="store_true", dest="disableLog", - default=False, - help="The filepath of the log file to be created") - -opa.add_option("--no-test-out", action="store_true", dest="disableTestStdOut", - default=False, - help="The filepath of the log file to be created") - -opa.add_option("-s", "--silent", action="store_true", dest="silent", default=False, - help="Disables display of all tests") - -opa.add_option("-v", "--verbose", action="store_true", dest="verbose", - default=False, - help="Displays all tests (only if --silent is not set)") - -opa.add_option("-x", "--max", type="int", dest="maxTestCount", - default="-1", - help="The maximum number of tests to be run") - -opa.add_option("-t", "--test", type="string", dest="singleTest", - default=None, - help="Runs the specified test only") - -opa.add_option("--rieo", "--report-internal-errors-only", action="store_true", - dest="reportInternalErrOnly", default=False, - help="Display erroneous tests of type 'internal' only") - -opa.add_option("--rmleo", "--report-mem-leak-errors-only", action="store_true", - dest="reportMemLeakErrOnly", default=False, - help="Display erroneous tests of type 'memory leak' only") - -opa.add_option("-c", "--combines", type="string", dest="combines", - default=None, - help="Combines to be run (all if omitted)") - -opa.add_option("--rc", "--report-combines", action="store_true", - dest="reportCombines", default=False, - help="Display combine reports") - -opa.add_option("--rec", "--report-err-combines", action="store_true", - dest="reportErrCombines", default=False, - help="Display erroneous combine reports only") - -opa.add_option("--debug", action="store_true", - dest="debugEnabled", default=False, - help="Displays debug messages") - -opa.add_option("--info", action="store_true", - dest="info", default=False, - help="Displays info on the suite only. Does not run any test.") - -(options, args) = opa.parse_args() - -if options.combines is not None: - options.combines = options.combines.split() - -################################################ -# The vars below are not intended to be changed. -# - -msgSchemaNotValidButShould = "The schema should be valid." -msgSchemaValidButShouldNot = "The schema should be invalid." -msgInstanceNotValidButShould = "The instance should be valid." -msgInstanceValidButShouldNot = "The instance should be invalid." -testFolderNIST = "nisttest" -testFolderMS = "msxsdtest" -testFolderSUN = "suntest" - -################### -# Helper functions. -# - -def handleError(test, msg): - test.addLibLog("'%s' LIB: %s" % (test.name, msg)) - if msg.find("Unimplemented") > -1: - test.failUnimplemented() - elif msg.find("Internal") > -1: - test.failInternal() - - -################## -# Test case class. -# - -class MSTestCase: - - def __init__(self, name, descr, tFolder, sFolder, sFile, sVal, iExists, iFolder, iFile, iVal): - global testFolderNIST, testFolderSUN, testFolderMS - # - # Init. - # - self.name = name - self.descr = descr - self.test_Folder = tFolder - self.schema_Folder = sFolder - self.schema_File = sFile - self.schema_Val = sVal - self.instance_Exists = iExists - self.instance_Folder = iFolder - self.instance_File = iFile - self.instance_Val = iVal - self.failed = False - self.log = [] - self.libLog = [] - self.phase = "" - self.initialMemUsed = 0 - self.memLeak = 0 - self.excepted = False - self.bad = False - self.unimplemented = False - self.internalErr = False - # - # Compute combine name of this test. - # - if self.test_Folder == testFolderMS or self.test_Folder == testFolderSUN: - # - # Use the last given directory for the combine name. - # - dirs = self.schema_Folder.split("/") - self.combineName = dirs[len(dirs) -1] - elif self.test_Folder == testFolderNIST: - # - # NIST files are named in the following form: - # "NISTSchema-short-pattern-1.xsd" - # - tokens = self.schema_File.split("-") - self.combineName = tokens[1] - else: - self.combineName = "unkown" - raise Exception("Could not compute the combine name of a test.") - # - # Init the log. - # - self.log.append("'%s' descr: %s\n" % (self.name, self.descr)) - self.log.append("'%s' exp schema valid: %d\n" % (self.name, self.schema_Val)) - if (self.instance_Exists): - self.log.append("'%s' exp instance valid: %d\n" % (self.name, self.schema_Val)) - - def addLibLog(self, msg): - """This one is intended to be used by the error handler - function""" - self.libLog.append(msg) - - def fail(self, msg): - self.failed = True - self.log.append("'%s' ( FAILED: %s\n" % (self.name, msg)) - - def failInternal(self): - self.failed = True - self.internalErr = True - self.log.append("'%s' * INTERNAL\n" % self.name) - - def failUnimplemented(self): - self.failed = True - self.unimplemented = True - self.log.append("'%s' ? UNIMPLEMENTED\n" % self.name) - - def failCritical(self, msg): - self.failed = True - self.bad = True - self.log.append("'%s' ! BAD: %s\n" % (self.name, msg)) - - def failExcept(self, e): - self.failed = True - self.excepted = True - self.log.append("'%s' # EXCEPTION: %s\n" % (self.name, e.__str__())) - - def setUp(self): - # - # Set up Libxml2. - # - self.initialMemUsed = libxml2.debugMemory(1) - libxml2.initParser() - libxml2.lineNumbersDefault(1) - libxml2.registerErrorHandler(handleError, self) - - def tearDown(self): - libxml2.schemaCleanupTypes() - libxml2.cleanupParser() - self.memLeak = libxml2.debugMemory(1) - self.initialMemUsed - - def isIOError(self, file, docType): - err = None - try: - err = libxml2.lastError() - except: - # Suppress exceptions. - pass - if (err is None): - return False - if err.domain() == libxml2.XML_FROM_IO: - self.failCritical("failed to access the %s resource '%s'\n" % (docType, file)) - - def debugMsg(self, msg): - global options - if options.debugEnabled: - sys.stdout.write("'%s' DEBUG: %s\n" % (self.name, msg)) - - def finalize(self): - """Adds additional info to the log.""" - # - # Add libxml2 messages. - # - self.log.extend(self.libLog) - # - # Add memory leaks. - # - if self.memLeak != 0: - self.log.append("%s + memory leak: %d bytes\n" % (self.name, self.memLeak)) - - def processSchema(self, filePath): - global msgSchemaNotValidButShould, msgSchemaValidButShouldNot - schema = None - - # - # Parse the schema. - # - self.debugMsg("loading schema: %s" % filePath) - schema_ParserCtxt = libxml2.schemaNewParserCtxt(filePath) - try: - try: - schema = schema_ParserCtxt.schemaParse() - except: - pass - finally: - self.debugMsg("after loading schema") - del schema_ParserCtxt - if schema is None: - self.debugMsg("schema is None") - self.debugMsg("checking for IO errors...") - if self.isIOError(file, "schema"): - return None - self.debugMsg("checking schema result") - if (schema is None and self.schema_Val) or (schema is not None and self.schema_Val == 0): - self.debugMsg("schema result is BAD") - if (schema == None): - self.fail(msgSchemaNotValidButShould) - else: - self.fail(msgSchemaValidButShouldNot) - else: - self.debugMsg("schema result is OK") - self.debugMsg("after checking schema result") - - def processInstance(self, filePath, schema): - global msgInstanceNotValidButShould, msgInstanceValidButShouldNot - - instance = None - self.debugMsg("loading instance: %s" % file) - instance_parserCtxt = libxml2.newParserCtxt() - if (instance_parserCtxt is None): - # TODO: Is this one necessary, or will an exception - # be already raised? - raise Exception("Could not create the instance parser context.") - try: - try: - instance = instance_parserCtxt.ctxtReadFile(file, None, libxml2.XML_PARSE_NOWARNING) - except: - # Suppress exceptions. - pass - finally: - del instance_parserCtxt - self.debugMsg("after loading instance") - if instance is None: - self.debugMsg("instance is None") - self.failCritical("Failed to parse the instance for unknown reasons.") - return - else: - try: - # - # Validate the instance. - # - validation_Ctxt = schema.schemaNewValidCtxt() - if (validation_Ctxt is None): - self.failCritical("Could not create the validation context.") - return - try: - self.debugMsg("validating instance") - instance_Err = validation_Ctxt.schemaValidateDoc(instance) - self.debugMsg("after instance validation") - self.debugMsg("instance-err: %d" % instance_Err) - if (instance_Err != 0 and self.instance_Val == 1) or (instance_Err == 0 and self.instance_Val == 0): - self.debugMsg("instance result is BAD") - if (instance_Err != 0): - self.fail(msgInstanceNotValidButShould) - else: - self.fail(msgInstanceValidButShouldNot) - - else: - self.debugMsg("instance result is OK") - finally: - del validation_Ctxt - finally: - instance.freeDoc() - - - def run(self): - """Runs a test.""" - global options - - # os.path.join(options.baseDir, self.test_Folder, self.schema_Folder, self.schema_File) - filePath = "%s/%s/%s/%s" % (options.baseDir, self.test_Folder, self.schema_Folder, self.schema_File) - schema = None - try: - schema = self.processSchema(filePath) - try: - if self.instance_Exists and (schema is not None) and (not self.failed): - file = "%s/%s/%s/%s" % (options.baseDir, self.test_Folder, self.instance_Folder, self.instance_File) - processInstance(filePath, schema) - finally: - if schema is not None: - del schema - - except Exception, e: - self.failExcept(e) - - -#################### -# Test runner class. -# - -class MSTestRunner: - - CNT_TOTAL = 0 - CNT_RAN = 1 - CNT_SUCCEEDED = 2 - CNT_FAILED = 3 - CNT_UNIMPLEMENTED = 4 - CNT_INTERNAL = 5 - CNT_BAD = 6 - CNT_EXCEPTED = 7 - CNT_MEMLEAK = 8 - - def __init__(self): - self.logFile = None - self.counters = self.createCounters() - self.testList = [] - self.combinesRan = {} - - def createCounters(self): - counters = {self.CNT_TOTAL:0, self.CNT_RAN:0, self.CNT_SUCCEEDED:0, - self.CNT_FAILED:0, self.CNT_UNIMPLEMENTED:0, self.CNT_INTERNAL:0, self.CNT_BAD:0, - self.CNT_EXCEPTED:0, self.CNT_MEMLEAK:0} - - return counters - - def addTest(self, test): - self.testList.append(test) - - def updateCounters(self, test, counters): - if test.memLeak != 0: - counters[self.CNT_MEMLEAK] += 1 - if not test.failed: - counters[self.CNT_SUCCEEDED] +=1 - if test.failed: - counters[self.CNT_FAILED] += 1 - if test.bad: - counters[self.CNT_BAD] += 1 - if test.unimplemented: - counters[self.CNT_UNIMPLEMENTED] += 1 - if test.internalErr: - counters[self.CNT_INTERNAL] += 1 - if test.excepted: - counters[self.CNT_EXCEPTED] += 1 - return counters - - def displayResults(self, out, all, combName, counters): - out.write("\n") - if all: - if options.combines is not None: - out.write("combine(s): %s\n" % str(options.combines)) - elif combName is not None: - out.write("combine : %s\n" % combName) - out.write(" total : %d\n" % counters[self.CNT_TOTAL]) - if all or options.combines is not None: - out.write(" ran : %d\n" % counters[self.CNT_RAN]) - # out.write(" succeeded : %d\n" % counters[self.CNT_SUCCEEDED]) - if counters[self.CNT_FAILED] > 0: - out.write(" failed : %d\n" % counters[self.CNT_FAILED]) - out.write(" -> internal : %d\n" % counters[self.CNT_INTERNAL]) - out.write(" -> unimpl. : %d\n" % counters[self.CNT_UNIMPLEMENTED]) - out.write(" -> bad : %d\n" % counters[self.CNT_BAD]) - out.write(" -> exceptions : %d\n" % counters[self.CNT_EXCEPTED]) - if counters[self.CNT_MEMLEAK] > 0: - out.write(" memory leaks : %d\n" % counters[self.CNT_MEMLEAK]) - - def reportCombine(self, combName): - global options - - counters = self.createCounters() - # - # Compute evaluation counters. - # - for test in self.combinesRan[combName]: - counters[self.CNT_TOTAL] += 1 - counters[self.CNT_RAN] += 1 - counters = self.updateCounters(test, counters) - if options.reportErrCombines and (counters[self.CNT_FAILED] == 0) and (counters[self.CNT_MEMLEAK] == 0): - pass - else: - if not options.disableLog: - self.displayResults(self.logFile, False, combName, counters) - self.displayResults(sys.stdout, False, combName, counters) - - def displayTestLog(self, test): - sys.stdout.writelines(test.log) - sys.stdout.write("~~~~~~~~~~\n") - - def reportTest(self, test): - global options - - error = test.failed or test.memLeak != 0 - # - # Only erroneous tests will be written to the log, - # except @verbose is switched on. - # - if not options.disableLog and (options.verbose or error): - self.logFile.writelines(test.log) - self.logFile.write("~~~~~~~~~~\n") - # - # if not @silent, only erroneous tests will be - # written to stdout, except @verbose is switched on. - # - if not options.silent: - if options.reportInternalErrOnly and test.internalErr: - self.displayTestLog(test) - if options.reportMemLeakErrOnly and test.memLeak != 0: - self.displayTestLog(test) - if (options.verbose or error) and (not options.reportInternalErrOnly) and (not options.reportMemLeakErrOnly): - self.displayTestLog(test) - - def addToCombines(self, test): - found = False - if self.combinesRan.has_key(test.combineName): - self.combinesRan[test.combineName].append(test) - else: - self.combinesRan[test.combineName] = [test] - - def run(self): - - global options - - if options.info: - for test in self.testList: - self.addToCombines(test) - sys.stdout.write("Combines: %d\n" % len(self.combinesRan)) - sys.stdout.write("%s\n" % self.combinesRan.keys()) - return - - if not options.disableLog: - self.logFile = open(options.logFile, "w") - try: - for test in self.testList: - self.counters[self.CNT_TOTAL] += 1 - # - # Filter tests. - # - if options.singleTest is not None and options.singleTest != "": - if (test.name != options.singleTest): - continue - elif options.combines is not None: - if not options.combines.__contains__(test.combineName): - continue - if options.maxTestCount != -1 and self.counters[self.CNT_RAN] >= options.maxTestCount: - break - self.counters[self.CNT_RAN] += 1 - # - # Run the thing, dammit. - # - try: - test.setUp() - try: - test.run() - finally: - test.tearDown() - finally: - # - # Evaluate. - # - test.finalize() - self.reportTest(test) - if options.reportCombines or options.reportErrCombines: - self.addToCombines(test) - self.counters = self.updateCounters(test, self.counters) - finally: - if options.reportCombines or options.reportErrCombines: - # - # Build a report for every single combine. - # - # TODO: How to sort a dict? - # - self.combinesRan.keys().sort(None) - for key in self.combinesRan.keys(): - self.reportCombine(key) - - # - # Display the final report. - # - sys.stdout.write("===========================\n") - self.displayResults(sys.stdout, True, None, self.counters) - -####### -# Main. -# +from xstc import MSTestRunner, MSTestCase r = MSTestRunner() @@ -540,7 +22,6 @@ r.run() # Display results. # - @@ -581,4 +62,4 @@ r.run() - \ No newline at end of file + diff --git a/xstc/xstc.py b/xstc/xstc.py new file mode 100755 index 00000000..538a92c6 --- /dev/null +++ b/xstc/xstc.py @@ -0,0 +1,542 @@ +# +# This is the MS subset of the W3C test suite for XML Schemas. +# This file is generated from the MS W3c test suite description file. +# + +import sys, os +import exceptions, optparse +import libxml2 + +opa = optparse.OptionParser() + +opa.add_option("-b", "--base", action="store", type="string", dest="baseDir", + default="", + help="""The base directory; i.e. the parent folder of the + "nisttest", "suntest" and "msxsdtest" directories.""") + +opa.add_option("-o", "--out", action="store", type="string", dest="logFile", + default="test.log", + help="The filepath of the log file to be created") + +opa.add_option("--no-log", action="store_true", dest="disableLog", + default=False, + help="The filepath of the log file to be created") + +opa.add_option("--no-test-out", action="store_true", dest="disableTestStdOut", + default=False, + help="The filepath of the log file to be created") + +opa.add_option("-s", "--silent", action="store_true", dest="silent", default=False, + help="Disables display of all tests") + +opa.add_option("-v", "--verbose", action="store_true", dest="verbose", + default=False, + help="Displays all tests (only if --silent is not set)") + +opa.add_option("-x", "--max", type="int", dest="maxTestCount", + default="-1", + help="The maximum number of tests to be run") + +opa.add_option("-t", "--test", type="string", dest="singleTest", + default=None, + help="Runs the specified test only") + +opa.add_option("--rieo", "--report-internal-errors-only", action="store_true", + dest="reportInternalErrOnly", default=False, + help="Display erroneous tests of type 'internal' only") + +opa.add_option("--rmleo", "--report-mem-leak-errors-only", action="store_true", + dest="reportMemLeakErrOnly", default=False, + help="Display erroneous tests of type 'memory leak' only") + +opa.add_option("-c", "--combines", type="string", dest="combines", + default=None, + help="Combines to be run (all if omitted)") + +opa.add_option("--rc", "--report-combines", action="store_true", + dest="reportCombines", default=False, + help="Display combine reports") + +opa.add_option("--rec", "--report-err-combines", action="store_true", + dest="reportErrCombines", default=False, + help="Display erroneous combine reports only") + +opa.add_option("--debug", action="store_true", + dest="debugEnabled", default=False, + help="Displays debug messages") + +opa.add_option("--info", action="store_true", + dest="info", default=False, + help="Displays info on the suite only. Does not run any test.") + +(options, args) = opa.parse_args() + +if options.combines is not None: + options.combines = options.combines.split() + +################################################ +# The vars below are not intended to be changed. +# + +msgSchemaNotValidButShould = "The schema should be valid." +msgSchemaValidButShouldNot = "The schema should be invalid." +msgInstanceNotValidButShould = "The instance should be valid." +msgInstanceValidButShouldNot = "The instance should be invalid." +testFolderNIST = "nisttest" +testFolderMS = "msxsdtest" +testFolderSUN = "suntest" + +################### +# Helper functions. +# + +def handleError(test, msg): + test.addLibLog("'%s' LIB: %s" % (test.name, msg)) + if msg.find("Unimplemented") > -1: + test.failUnimplemented() + elif msg.find("Internal") > -1: + test.failInternal() + + +################## +# Test case class. +# + +class MSTestCase: + + def __init__(self, name, descr, tFolder, sFolder, sFile, sVal, iExists, iFolder, iFile, iVal): + global testFolderNIST, testFolderSUN, testFolderMS + # + # Init. + # + self.name = name + self.descr = descr + self.test_Folder = tFolder + self.schema_Folder = sFolder + self.schema_File = sFile + self.schema_Val = sVal + self.instance_Exists = iExists + self.instance_Folder = iFolder + self.instance_File = iFile + self.instance_Val = iVal + self.failed = False + self.log = [] + self.libLog = [] + self.phase = "" + self.initialMemUsed = 0 + self.memLeak = 0 + self.excepted = False + self.bad = False + self.unimplemented = False + self.internalErr = False + # + # Compute combine name of this test. + # + if self.test_Folder == testFolderMS or self.test_Folder == testFolderSUN: + # + # Use the last given directory for the combine name. + # + dirs = self.schema_Folder.split("/") + self.combineName = dirs[len(dirs) -1] + elif self.test_Folder == testFolderNIST: + # + # NIST files are named in the following form: + # "NISTSchema-short-pattern-1.xsd" + # + tokens = self.schema_File.split("-") + self.combineName = tokens[1] + else: + self.combineName = "unkown" + raise Exception("Could not compute the combine name of a test.") + # + # Init the log. + # + self.log.append("'%s' descr: %s\n" % (self.name, self.descr)) + self.log.append("'%s' exp schema valid: %d\n" % (self.name, self.schema_Val)) + if (self.instance_Exists): + self.log.append("'%s' exp instance valid: %d\n" % (self.name, self.schema_Val)) + + def addLibLog(self, msg): + """This one is intended to be used by the error handler + function""" + self.libLog.append(msg) + + def fail(self, msg): + self.failed = True + self.log.append("'%s' ( FAILED: %s\n" % (self.name, msg)) + + def failInternal(self): + self.failed = True + self.internalErr = True + self.log.append("'%s' * INTERNAL\n" % self.name) + + def failUnimplemented(self): + self.failed = True + self.unimplemented = True + self.log.append("'%s' ? UNIMPLEMENTED\n" % self.name) + + def failCritical(self, msg): + self.failed = True + self.bad = True + self.log.append("'%s' ! BAD: %s\n" % (self.name, msg)) + + def failExcept(self, e): + self.failed = True + self.excepted = True + self.log.append("'%s' # EXCEPTION: %s\n" % (self.name, e.__str__())) + + def setUp(self): + # + # Set up Libxml2. + # + self.initialMemUsed = libxml2.debugMemory(1) + libxml2.initParser() + libxml2.lineNumbersDefault(1) + libxml2.registerErrorHandler(handleError, self) + + def tearDown(self): + libxml2.schemaCleanupTypes() + libxml2.cleanupParser() + self.memLeak = libxml2.debugMemory(1) - self.initialMemUsed + + def isIOError(self, file, docType): + err = None + try: + err = libxml2.lastError() + except: + # Suppress exceptions. + pass + if (err is None): + return False + if err.domain() == libxml2.XML_FROM_IO: + self.failCritical("failed to access the %s resource '%s'\n" % (docType, file)) + + def debugMsg(self, msg): + global options + if options.debugEnabled: + sys.stdout.write("'%s' DEBUG: %s\n" % (self.name, msg)) + + def finalize(self): + """Adds additional info to the log.""" + # + # Add libxml2 messages. + # + self.log.extend(self.libLog) + # + # Add memory leaks. + # + if self.memLeak != 0: + self.log.append("%s + memory leak: %d bytes\n" % (self.name, self.memLeak)) + + def processSchema(self, filePath): + global msgSchemaNotValidButShould, msgSchemaValidButShouldNot + schema = None + + # + # Parse the schema. + # + self.debugMsg("loading schema: %s" % filePath) + schema_ParserCtxt = libxml2.schemaNewParserCtxt(filePath) + try: + try: + schema = schema_ParserCtxt.schemaParse() + except: + pass + finally: + self.debugMsg("after loading schema") + del schema_ParserCtxt + if schema is None: + self.debugMsg("schema is None") + self.debugMsg("checking for IO errors...") + if self.isIOError(file, "schema"): + return None + self.debugMsg("checking schema result") + if (schema is None and self.schema_Val) or (schema is not None and self.schema_Val == 0): + self.debugMsg("schema result is BAD") + if (schema == None): + self.fail(msgSchemaNotValidButShould) + else: + self.fail(msgSchemaValidButShouldNot) + else: + self.debugMsg("schema result is OK") + self.debugMsg("after checking schema result") + + def processInstance(self, filePath, schema): + global msgInstanceNotValidButShould, msgInstanceValidButShouldNot + + instance = None + self.debugMsg("loading instance: %s" % file) + instance_parserCtxt = libxml2.newParserCtxt() + if (instance_parserCtxt is None): + # TODO: Is this one necessary, or will an exception + # be already raised? + raise Exception("Could not create the instance parser context.") + try: + try: + instance = instance_parserCtxt.ctxtReadFile(file, None, libxml2.XML_PARSE_NOWARNING) + except: + # Suppress exceptions. + pass + finally: + del instance_parserCtxt + self.debugMsg("after loading instance") + if instance is None: + self.debugMsg("instance is None") + self.failCritical("Failed to parse the instance for unknown reasons.") + return + else: + try: + # + # Validate the instance. + # + validation_Ctxt = schema.schemaNewValidCtxt() + if (validation_Ctxt is None): + self.failCritical("Could not create the validation context.") + return + try: + self.debugMsg("validating instance") + instance_Err = validation_Ctxt.schemaValidateDoc(instance) + self.debugMsg("after instance validation") + self.debugMsg("instance-err: %d" % instance_Err) + if (instance_Err != 0 and self.instance_Val == 1) or (instance_Err == 0 and self.instance_Val == 0): + self.debugMsg("instance result is BAD") + if (instance_Err != 0): + self.fail(msgInstanceNotValidButShould) + else: + self.fail(msgInstanceValidButShouldNot) + + else: + self.debugMsg("instance result is OK") + finally: + del validation_Ctxt + finally: + instance.freeDoc() + + + def run(self): + """Runs a test.""" + global options + + # os.path.join(options.baseDir, self.test_Folder, self.schema_Folder, self.schema_File) + filePath = "%s/%s/%s/%s" % (options.baseDir, self.test_Folder, self.schema_Folder, self.schema_File) + schema = None + try: + schema = self.processSchema(filePath) + try: + if self.instance_Exists and (schema is not None) and (not self.failed): + file = "%s/%s/%s/%s" % (options.baseDir, self.test_Folder, self.instance_Folder, self.instance_File) + processInstance(filePath, schema) + finally: + if schema is not None: + del schema + + except Exception, e: + self.failExcept(e) + + +#################### +# Test runner class. +# + +class MSTestRunner: + + CNT_TOTAL = 0 + CNT_RAN = 1 + CNT_SUCCEEDED = 2 + CNT_FAILED = 3 + CNT_UNIMPLEMENTED = 4 + CNT_INTERNAL = 5 + CNT_BAD = 6 + CNT_EXCEPTED = 7 + CNT_MEMLEAK = 8 + + def __init__(self): + self.logFile = None + self.counters = self.createCounters() + self.testList = [] + self.combinesRan = {} + + def createCounters(self): + counters = {self.CNT_TOTAL:0, self.CNT_RAN:0, self.CNT_SUCCEEDED:0, + self.CNT_FAILED:0, self.CNT_UNIMPLEMENTED:0, self.CNT_INTERNAL:0, self.CNT_BAD:0, + self.CNT_EXCEPTED:0, self.CNT_MEMLEAK:0} + + return counters + + def addTest(self, test): + self.testList.append(test) + + def updateCounters(self, test, counters): + if test.memLeak != 0: + counters[self.CNT_MEMLEAK] += 1 + if not test.failed: + counters[self.CNT_SUCCEEDED] +=1 + if test.failed: + counters[self.CNT_FAILED] += 1 + if test.bad: + counters[self.CNT_BAD] += 1 + if test.unimplemented: + counters[self.CNT_UNIMPLEMENTED] += 1 + if test.internalErr: + counters[self.CNT_INTERNAL] += 1 + if test.excepted: + counters[self.CNT_EXCEPTED] += 1 + return counters + + def displayResults(self, out, all, combName, counters): + out.write("\n") + if all: + if options.combines is not None: + out.write("combine(s): %s\n" % str(options.combines)) + elif combName is not None: + out.write("combine : %s\n" % combName) + out.write(" total : %d\n" % counters[self.CNT_TOTAL]) + if all or options.combines is not None: + out.write(" ran : %d\n" % counters[self.CNT_RAN]) + # out.write(" succeeded : %d\n" % counters[self.CNT_SUCCEEDED]) + if counters[self.CNT_FAILED] > 0: + out.write(" failed : %d\n" % counters[self.CNT_FAILED]) + out.write(" -> internal : %d\n" % counters[self.CNT_INTERNAL]) + out.write(" -> unimpl. : %d\n" % counters[self.CNT_UNIMPLEMENTED]) + out.write(" -> bad : %d\n" % counters[self.CNT_BAD]) + out.write(" -> exceptions : %d\n" % counters[self.CNT_EXCEPTED]) + if counters[self.CNT_MEMLEAK] > 0: + out.write(" memory leaks : %d\n" % counters[self.CNT_MEMLEAK]) + + def displayShortResults(self, out, all, combName, counters): + out.write("Ran %d of %d tests:" % (counters[self.CNT_RAN], + counters[self.CNT_TOTAL])) + # out.write(" succeeded : %d\n" % counters[self.CNT_SUCCEEDED]) + if counters[self.CNT_FAILED] > 0 or counters[self.CNT_MEMLEAK] > 0: + out.write(" %d failed" % (counters[self.CNT_FAILED])) + if counters[self.CNT_INTERNAL] > 0: + out.write(" %d internal" % (counters[self.CNT_INTERNAL])) + if counters[self.CNT_UNIMPLEMENTED] > 0: + out.write(" %d unimplemented" % (counters[self.CNT_UNIMPLEMENTED])) + if counters[self.CNT_BAD] > 0: + out.write(" %d bad" % (counters[self.CNT_BAD])) + if counters[self.CNT_EXCEPTED] > 0: + out.write(" %d exception" % (counters[self.CNT_EXCEPTED])) + if counters[self.CNT_MEMLEAK] > 0: + out.write(" %d leaks" % (counters[self.CNT_MEMLEAK])) + out.write("\n") + else: + out.write("all passed\n") + + def reportCombine(self, combName): + global options + + counters = self.createCounters() + # + # Compute evaluation counters. + # + for test in self.combinesRan[combName]: + counters[self.CNT_TOTAL] += 1 + counters[self.CNT_RAN] += 1 + counters = self.updateCounters(test, counters) + if options.reportErrCombines and (counters[self.CNT_FAILED] == 0) and (counters[self.CNT_MEMLEAK] == 0): + pass + else: + if not options.disableLog: + self.displayResults(self.logFile, False, combName, counters) + self.displayResults(sys.stdout, False, combName, counters) + + def displayTestLog(self, test): + sys.stdout.writelines(test.log) + sys.stdout.write("~~~~~~~~~~\n") + + def reportTest(self, test): + global options + + error = test.failed or test.memLeak != 0 + # + # Only erroneous tests will be written to the log, + # except @verbose is switched on. + # + if not options.disableLog and (options.verbose or error): + self.logFile.writelines(test.log) + self.logFile.write("~~~~~~~~~~\n") + # + # if not @silent, only erroneous tests will be + # written to stdout, except @verbose is switched on. + # + if not options.silent: + if options.reportInternalErrOnly and test.internalErr: + self.displayTestLog(test) + if options.reportMemLeakErrOnly and test.memLeak != 0: + self.displayTestLog(test) + if (options.verbose or error) and (not options.reportInternalErrOnly) and (not options.reportMemLeakErrOnly): + self.displayTestLog(test) + + def addToCombines(self, test): + found = False + if self.combinesRan.has_key(test.combineName): + self.combinesRan[test.combineName].append(test) + else: + self.combinesRan[test.combineName] = [test] + + def run(self): + + global options + + if options.info: + for test in self.testList: + self.addToCombines(test) + sys.stdout.write("Combines: %d\n" % len(self.combinesRan)) + sys.stdout.write("%s\n" % self.combinesRan.keys()) + return + + if not options.disableLog: + self.logFile = open(options.logFile, "w") + try: + for test in self.testList: + self.counters[self.CNT_TOTAL] += 1 + # + # Filter tests. + # + if options.singleTest is not None and options.singleTest != "": + if (test.name != options.singleTest): + continue + elif options.combines is not None: + if not options.combines.__contains__(test.combineName): + continue + if options.maxTestCount != -1 and self.counters[self.CNT_RAN] >= options.maxTestCount: + break + self.counters[self.CNT_RAN] += 1 + # + # Run the thing, dammit. + # + try: + test.setUp() + try: + test.run() + finally: + test.tearDown() + finally: + # + # Evaluate. + # + test.finalize() + self.reportTest(test) + if options.reportCombines or options.reportErrCombines: + self.addToCombines(test) + self.counters = self.updateCounters(test, self.counters) + finally: + if options.reportCombines or options.reportErrCombines: + # + # Build a report for every single combine. + # + # TODO: How to sort a dict? + # + self.combinesRan.keys().sort(None) + for key in self.combinesRan.keys(): + self.reportCombine(key) + + # + # Display the final report. + # + if options.silent: + self.displayShortResults(sys.stdout, True, None, self.counters) + else: + sys.stdout.write("===========================\n") + self.displayResults(sys.stdout, True, None, self.counters) -- cgit v1.2.1