|
#!/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)) |