"""usage:
test-to-xml.py infile.txt outfile.xml
"""
import re
import codecs
from xml.dom.minidom import getDOMImplementation
__all__ = ['compileTests']
# === Object model and XML generation
# tests: test*
# test: @title, step*
# step: expr output* (result | error)?
def element(parent, name):
e = parent.ownerDocument.createElement(name)
parent.appendChild(e)
return e
def text_element(parent, name, text):
e = element(parent, name)
e.appendChild(parent.ownerDocument.createTextNode(text))
return e
class Step:
def __init__(self):
self.parts = []
def add_expr(self, text):
self.parts.append((u'expr', text))
def add_output(self, text):
self.parts.append((u'output', text))
def add_result(self, text):
self.parts.append((u'result', text))
def to_xml(self, parent):
e = element(parent, u'step')
for tagname, value in self.parts:
text_element(e, tagname, value)
return e
class Test:
def __init__(self, title):
self.title = title
self.steps = []
def add(self, step):
self.steps.append(step)
def to_xml(self, parent):
e = element(parent, u'test')
e.setAttribute(u'title', self.title)
for s in self.steps:
s.to_xml(e)
return e
class TestFile:
def __init__(self):
self.tests = []
def add(self, test):
self.tests.append(test)
def save_as_xml(self, filename):
impl = getDOMImplementation()
doc = impl.createDocument(None, u'tests', None)
root = doc.documentElement
for g in self.tests:
g.to_xml(root)
f = open(filename, 'wb')
doc.writexml(f, addindent="\t", newl="\n")
f.close()
### === Parsing input file
token_re = re.compile(r"""(?ux)
\s*
(
;.*$
| [()`',]
| \#\(
| [\w\-\+.<>=!@#\$%\^&\*_\'/\?]+
| "[^\"]*"
)
""")
def parse_step(step_text):
st = Step()
point = 0
add = st.add_expr
for m in re.finditer(token_re, step_text):
tkn = m.group(1)
if tkn in ('===>', '>>'):
chunk = step_text[point:m.start(1)]
add(chunk.strip())
point = m.end(1)
if tkn == '===>':
add = st.add_result
else:
add = st.add_output
remainder = step_text[point:]
add(remainder.strip())
return st
def is_header(stripped):
return stripped.startswith('===')
def compileTests(in_file, out_file):
f = codecs.open(in_file, 'r', 'utf-8')
text = f.read()
f.close()
paragraphs = text.replace('\r\n', '\n').split('\n\n')
doc = TestFile()
current_test = None
for para in paragraphs:
stripped = re.sub(ur'(?m);.*$', u'', para).strip()
if is_header(stripped):
title = stripped[3:].strip()
current_test = Test(title)
doc.add(current_test)
elif stripped == u'':
pass
elif current_test is None:
raise ValueError("need === header line at top of file")
else:
current_test.add(parse_step(para))
doc.save_as_xml(out_file)
if __name__ == '__main__':
import sys
if len(sys.argv) != 3:
print __doc__
else:
compileTests(sys.argv[1], sys.argv[2])