| #!/usr/bin/env python |
| |
| # |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| # |
| |
| # |
| # Convert rules to tests |
| # |
| import sys, re, os.path |
| from getopt import getopt, GetoptError |
| from string import capitalize |
| from xml import dom |
| from xml.dom.minidom import parse |
| |
| def camelcase(s): |
| """Convert 'string like this' to 'StringLikeThis'""" |
| return "".join([capitalize(w) for w in re.split(re.compile("\W*"), s)]) |
| |
| def uncapitalize(s): return s[0].lower()+s[1:] |
| |
| def ancestors(node): |
| "Return iterator of ancestors from top-level element to node" |
| def generator(node): |
| while node and node.parentNode: |
| yield node |
| node = node.parentNode |
| return reversed(list(generator(node))) |
| |
| def tagAndName(element): |
| nameAttr = element.getAttribute("name"); |
| if (nameAttr) : return camelcase(nameAttr) + camelcase(element.tagName) |
| else: return camelcase(element.tagName) |
| |
| def nodeText(n): |
| """Recursively collect text from all text nodes under n""" |
| if n.nodeType == dom.Node.TEXT_NODE: |
| return n.data |
| if n.childNodes: |
| return reduce(lambda t, c: t + nodeText(c), n.childNodes, "") |
| return "" |
| |
| def cleanup(docString, level=8): |
| unindent = re.sub("\n[ \t]*", "\n", docString.strip()) |
| emptyLines = re.sub("\n\n\n", "\n\n", unindent) |
| indented = re.sub("\n", "\n"+level*" ", emptyLines) |
| return level*" " + indented |
| |
| def printTest(test, docstring): |
| print "class %s(TestBase):" % test |
| print ' """' |
| print docstring |
| print ' """' |
| print |
| print |
| |
| def printTests(doc, module): |
| """Returns dictionary { classname : [ (methodname, docstring)* ] * }""" |
| tests = {} |
| rules = doc.getElementsByTagName("rule") |
| for r in rules: |
| path = list(ancestors(r)) |
| if module == path[1].getAttribute("name").lower(): |
| test = "".join(map(tagAndName, path[2:])) + "Tests" |
| docstring = cleanup(nodeText(r), 4) |
| printTest(test, docstring) |
| |
| def usage(message=None): |
| if message: print >>sys.stderr, message |
| print >>sys.stderr, """ |
| rule2test [options] <amqpclass> |
| |
| Print test classes for each rule for the amqpclass in amqp.xml. |
| |
| Options: |
| -?/-h/--help : this message |
| -s/--spec <spec.xml> : file containing amqp XML spec |
| """ |
| return 1 |
| |
| def main(argv): |
| try: opts, args = getopt(argv[1:], "h?s:", ["help", "spec="]) |
| except GetoptError, e: return usage(e) |
| spec = "../specs/amqp.xml" # Default |
| for opt, val in opts: |
| if (opt in ("-h", "-?", "--help")): return usage() |
| if (opt in ("-s", "--spec")): spec = val |
| doc = parse(spec) |
| if len(args) == 0: return usage() |
| printTests(doc, args[0]) |
| return 0 |
| |
| if (__name__ == "__main__"): sys.exit(main(sys.argv)) |