summaryrefslogtreecommitdiff
path: root/trunk/src/examples/TAP.py
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/examples/TAP.py')
-rw-r--r--trunk/src/examples/TAP.py217
1 files changed, 217 insertions, 0 deletions
diff --git a/trunk/src/examples/TAP.py b/trunk/src/examples/TAP.py
new file mode 100644
index 0000000..139e47c
--- /dev/null
+++ b/trunk/src/examples/TAP.py
@@ -0,0 +1,217 @@
+#
+# TAP.py - TAP parser
+#
+# A pyparsing parser to process the output of the Perl
+# "Test Anything Protocol"
+# (http://search.cpan.org/~petdance/TAP-1.00/TAP.pm)
+#
+# TAP output lines are preceded or followed by a test number range:
+# 1..n
+# with 'n' TAP output lines.
+#
+# The general format of a TAP output line is:
+# ok/not ok (required)
+# Test number (recommended)
+# Description (recommended)
+# Directive (only when necessary)
+#
+# A TAP output line may also indicate abort of the test suit with the line:
+# Bail out!
+# optionally followed by a reason for bailing
+#
+# Copyright 2008, by Paul McGuire
+#
+
+from pyparsing import ParserElement,LineEnd,Optional,Word,nums,Regex,\
+ Literal,CaselessLiteral,Group,OneOrMore,Suppress,restOfLine,\
+ FollowedBy,empty
+
+__all__ = ['tapOutputParser', 'TAPTest', 'TAPSummary']
+
+# newlines are significant whitespace, so set default skippable
+# whitespace to just spaces and tabs
+ParserElement.setDefaultWhitespaceChars(" \t")
+NL = LineEnd().suppress()
+
+integer = Word(nums)
+plan = '1..' + integer("ubound")
+
+OK,NOT_OK = map(Literal,['ok','not ok'])
+testStatus = (OK | NOT_OK)
+
+description = Regex("[^#\n]+")
+description.setParseAction(lambda t:t[0].lstrip('- '))
+
+TODO,SKIP = map(CaselessLiteral,'TODO SKIP'.split())
+directive = Group(Suppress('#') + (TODO + restOfLine |
+ FollowedBy(SKIP) +
+ restOfLine.copy().setParseAction(lambda t:['SKIP',t[0]]) ))
+
+commentLine = Suppress("#") + empty + restOfLine
+
+testLine = Group(
+ Optional(OneOrMore(commentLine + NL))("comments") +
+ testStatus("passed") +
+ Optional(integer)("testNumber") +
+ Optional(description)("description") +
+ Optional(directive)("directive")
+ )
+bailLine = Group(Literal("Bail out!")("BAIL") +
+ empty + Optional(restOfLine)("reason"))
+
+tapOutputParser = Optional(Group(plan)("plan") + NL) & \
+ Group(OneOrMore((testLine|bailLine) + NL))("tests")
+
+class TAPTest(object):
+ def __init__(self,results):
+ self.num = results.testNumber
+ self.passed = (results.passed=="ok")
+ self.skipped = self.todo = False
+ if results.directive:
+ self.skipped = (results.directive[0][0]=='SKIP')
+ self.todo = (results.directive[0][0]=='TODO')
+ @classmethod
+ def bailedTest(cls,num):
+ ret = TAPTest(empty.parseString(""))
+ ret.num = num
+ ret.skipped = True
+ return ret
+
+class TAPSummary(object):
+ def __init__(self,results):
+ self.passedTests = []
+ self.failedTests = []
+ self.skippedTests = []
+ self.todoTests = []
+ self.bonusTests = []
+ self.bail = False
+ if results.plan:
+ expected = list(range(1, int(results.plan.ubound)+1))
+ else:
+ expected = list(range(1,len(results.tests)+1))
+
+ for i,res in enumerate(results.tests):
+ # test for bail out
+ if res.BAIL:
+ #~ print "Test suite aborted: " + res.reason
+ #~ self.failedTests += expected[i:]
+ self.bail = True
+ self.skippedTests += [ TAPTest.bailedTest(ii) for ii in expected[i:] ]
+ self.bailReason = res.reason
+ break
+
+ #~ print res.dump()
+ testnum = i+1
+ if res.testNumber != "":
+ if testnum != int(res.testNumber):
+ print("ERROR! test %(testNumber)s out of sequence" % res)
+ testnum = int(res.testNumber)
+ res["testNumber"] = testnum
+
+ test = TAPTest(res)
+ if test.passed:
+ self.passedTests.append(test)
+ else:
+ self.failedTests.append(test)
+ if test.skipped: self.skippedTests.append(test)
+ if test.todo: self.todoTests.append(test)
+ if test.todo and test.passed: self.bonusTests.append(test)
+
+ self.passedSuite = not self.bail and (set(self.failedTests)-set(self.todoTests) == set())
+
+ def summary(self, showPassed=False, showAll=False):
+ testListStr = lambda tl : "[" + ",".join(str(t.num) for t in tl) + "]"
+ summaryText = []
+ if showPassed or showAll:
+ summaryText.append( "PASSED: %s" % testListStr(self.passedTests) )
+ if self.failedTests or showAll:
+ summaryText.append( "FAILED: %s" % testListStr(self.failedTests) )
+ if self.skippedTests or showAll:
+ summaryText.append( "SKIPPED: %s" % testListStr(self.skippedTests) )
+ if self.todoTests or showAll:
+ summaryText.append( "TODO: %s" % testListStr(self.todoTests) )
+ if self.bonusTests or showAll:
+ summaryText.append( "BONUS: %s" % testListStr(self.bonusTests) )
+ if self.passedSuite:
+ summaryText.append( "PASSED" )
+ else:
+ summaryText.append( "FAILED" )
+ return "\n".join(summaryText)
+
+# create TAPSummary objects from tapOutput parsed results, by setting
+# class as parse action
+tapOutputParser.setParseAction(TAPSummary)
+
+
+if __name__ == "__main__":
+ test1 = """\
+ 1..4
+ ok 1 - Input file opened
+ not ok 2 - First line of the input valid
+ ok 3 - Read the rest of the file
+ not ok 4 - Summarized correctly # TODO Not written yet
+ """
+ test2 = """\
+ ok 1
+ not ok 2 some description # TODO with a directive
+ ok 3 a description only, no directive
+ ok 4 # TODO directive only
+ ok a description only, no directive
+ ok # Skipped only a directive, no description
+ ok
+ """
+ test3 = """\
+ ok - created Board
+ ok
+ ok
+ not ok
+ ok
+ ok
+ ok
+ ok
+ # +------+------+------+------+
+ # | |16G | |05C |
+ # | |G N C | |C C G |
+ # | | G | | C +|
+ # +------+------+------+------+
+ # |10C |01G | |03C |
+ # |R N G |G A G | |C C C |
+ # | R | G | | C +|
+ # +------+------+------+------+
+ # | |01G |17C |00C |
+ # | |G A G |G N R |R N R |
+ # | | G | R | G |
+ # +------+------+------+------+
+ ok - board has 7 tiles + starter tile
+ 1..9
+ """
+ test4 = """\
+ 1..4
+ ok 1 - Creating test program
+ ok 2 - Test program runs, no error
+ not ok 3 - infinite loop # TODO halting problem unsolved
+ not ok 4 - infinite loop 2 # TODO halting problem unsolved
+ """
+ test5 = """\
+ 1..20
+ ok - database handle
+ not ok - failed database login
+ Bail out! Couldn't connect to database.
+ """
+ test6 = """\
+ ok 1 - retrieving servers from the database
+ # need to ping 6 servers
+ ok 2 - pinged diamond
+ ok 3 - pinged ruby
+ not ok 4 - pinged sapphire
+ ok 5 - pinged onyx
+ not ok 6 - pinged quartz
+ ok 7 - pinged gold
+ 1..7
+ """
+
+ for test in (test1,test2,test3,test4,test5,test6):
+ print(test)
+ tapResult = tapOutputParser.parseString(test)[0]
+ print(tapResult.summary(showAll=True))
+ print()