1 | #!/usr/bin/python
|
---|
2 | #
|
---|
3 | # tap2subunit: convert a tap stream to a subunit stream.
|
---|
4 | # Extract from the subunit source:
|
---|
5 | # Copyright (C) 2005 Robert Collins <robertc@robertcollins.net>
|
---|
6 | #
|
---|
7 | # Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
|
---|
8 | # license at the users choice. A copy of both licenses are available in the
|
---|
9 | # project source as Apache-2.0 and BSD. You may not use this file except in
|
---|
10 | # compliance with one of these two licences.
|
---|
11 | #
|
---|
12 | # Unless required by applicable law or agreed to in writing, software
|
---|
13 | # distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
|
---|
14 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
---|
15 | # license you chose for the specific language governing permissions and
|
---|
16 | # limitations under that license.
|
---|
17 | #
|
---|
18 |
|
---|
19 |
|
---|
20 | import re
|
---|
21 | import sys
|
---|
22 |
|
---|
23 | def TAP2SubUnit(tap, subunit):
|
---|
24 | """Filter a TAP pipe into a subunit pipe.
|
---|
25 |
|
---|
26 | :param tap: A tap pipe/stream/file object.
|
---|
27 | :param subunit: A pipe/stream/file object to write subunit results to.
|
---|
28 | :return: The exit code to exit with.
|
---|
29 | """
|
---|
30 | BEFORE_PLAN = 0
|
---|
31 | AFTER_PLAN = 1
|
---|
32 | SKIP_STREAM = 2
|
---|
33 | state = BEFORE_PLAN
|
---|
34 | plan_start = 1
|
---|
35 | plan_stop = 0
|
---|
36 | def _skipped_test(subunit, plan_start):
|
---|
37 | # Some tests were skipped.
|
---|
38 | subunit.write('test: test %d\n' % plan_start)
|
---|
39 | subunit.write('error: test %d [\n' % plan_start)
|
---|
40 | subunit.write('test missing from TAP output\n')
|
---|
41 | subunit.write(']\n')
|
---|
42 | return plan_start + 1
|
---|
43 | # Test data for the next test to emit
|
---|
44 | test_name = None
|
---|
45 | log = []
|
---|
46 | result = None
|
---|
47 | def _emit_test():
|
---|
48 | "write out a test"
|
---|
49 | if test_name is None:
|
---|
50 | return
|
---|
51 | subunit.write("test: %s\n" % test_name)
|
---|
52 | if not log:
|
---|
53 | subunit.write("%s: %s\n" % (result, test_name))
|
---|
54 | else:
|
---|
55 | subunit.write("%s: %s [\n" % (result, test_name))
|
---|
56 | if log:
|
---|
57 | for line in log:
|
---|
58 | subunit.write("%s\n" % line)
|
---|
59 | subunit.write("]\n")
|
---|
60 | del log[:]
|
---|
61 | for line in tap:
|
---|
62 | if state == BEFORE_PLAN:
|
---|
63 | match = re.match("(\d+)\.\.(\d+)\s*(?:\#\s+(.*))?\n", line)
|
---|
64 | if match:
|
---|
65 | state = AFTER_PLAN
|
---|
66 | _, plan_stop, comment = match.groups()
|
---|
67 | plan_stop = int(plan_stop)
|
---|
68 | if plan_start > plan_stop and plan_stop == 0:
|
---|
69 | # skipped file
|
---|
70 | state = SKIP_STREAM
|
---|
71 | subunit.write("test: file skip\n")
|
---|
72 | subunit.write("skip: file skip [\n")
|
---|
73 | subunit.write("%s\n" % comment)
|
---|
74 | subunit.write("]\n")
|
---|
75 | continue
|
---|
76 | # not a plan line, or have seen one before
|
---|
77 | match = re.match("(ok|not ok)(?:\s+(\d+)?)?(?:\s+([^#]*[^#\s]+)\s*)?(?:\s+#\s+(TODO|SKIP|skip|todo)(?:\s+(.*))?)?\n", line)
|
---|
78 | if match:
|
---|
79 | # new test, emit current one.
|
---|
80 | _emit_test()
|
---|
81 | status, number, description, directive, directive_comment = match.groups()
|
---|
82 | if status == 'ok':
|
---|
83 | result = 'success'
|
---|
84 | else:
|
---|
85 | result = "failure"
|
---|
86 | if description is None:
|
---|
87 | description = ''
|
---|
88 | else:
|
---|
89 | description = ' ' + description
|
---|
90 | if directive is not None:
|
---|
91 | if directive.upper() == 'TODO':
|
---|
92 | result = 'xfail'
|
---|
93 | elif directive.upper() == 'SKIP':
|
---|
94 | result = 'skip'
|
---|
95 | if directive_comment is not None:
|
---|
96 | log.append(directive_comment)
|
---|
97 | if number is not None:
|
---|
98 | number = int(number)
|
---|
99 | while plan_start < number:
|
---|
100 | plan_start = _skipped_test(subunit, plan_start)
|
---|
101 | test_name = "test %d%s" % (plan_start, description)
|
---|
102 | plan_start += 1
|
---|
103 | continue
|
---|
104 | match = re.match("Bail out\!(?:\s*(.*))?\n", line)
|
---|
105 | if match:
|
---|
106 | reason, = match.groups()
|
---|
107 | if reason is None:
|
---|
108 | extra = ''
|
---|
109 | else:
|
---|
110 | extra = ' %s' % reason
|
---|
111 | _emit_test()
|
---|
112 | test_name = "Bail out!%s" % extra
|
---|
113 | result = "error"
|
---|
114 | state = SKIP_STREAM
|
---|
115 | continue
|
---|
116 | match = re.match("\#.*\n", line)
|
---|
117 | if match:
|
---|
118 | log.append(line[:-1])
|
---|
119 | continue
|
---|
120 | subunit.write(line)
|
---|
121 | _emit_test()
|
---|
122 | while plan_start <= plan_stop:
|
---|
123 | # record missed tests
|
---|
124 | plan_start = _skipped_test(subunit, plan_start)
|
---|
125 | return 0
|
---|
126 |
|
---|
127 |
|
---|
128 | sys.exit(TAP2SubUnit(sys.stdin, sys.stdout))
|
---|