3 # Copyright (c) 2016 Cisco and/or its affiliates.
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at:
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
16 """Script extracts intersted data (name, documentation, message, status) from
17 robot framework output file (output.xml) and print in specified format (wiki,
18 html) to stdout or, if specified by parameter, redirect to file."""
24 from robot.api import ExecutionResult, ResultVisitor
27 class ExecutionChecker(ResultVisitor):
28 """Abstract class to traverse through the test suite structure."""
30 def __init__(self, args):
31 self.formatting = args.formatting
33 def visit_suite(self, suite):
34 """Implements traversing through the suite and its direct children.
36 :param suite: Suite to process.
41 if self.start_suite(suite) is not False:
43 if self.formatting == 'html':
44 sys.stdout.write('<table width=100% border=1><tr>'+'\n')
45 sys.stdout.write('<th width=32%>Name</th>'+'\n')
46 sys.stdout.write('<th width=40%>Documentation</th>'+'\n')
47 if "Perf" and "Long" in suite.longname:
48 sys.stdout.write('<th width=24%>Message</th>'+'\n')
49 sys.stdout.write('<th width=4%>Status</th><tr/>'+'\n')
50 sys.stdout.write('</tr>')
51 elif self.formatting == 'wiki':
52 sys.stdout.write('{| class="wikitable"'+'\n')
53 if "Perf" and "Long" in suite.longname:
54 header = '!Name!!Documentation!!Message!!Status'
56 header = '!Name!!Documentation!!Status'
57 sys.stdout.write(header+'\n')
61 suite.suites.visit(self)
62 suite.tests.visit(self)
65 if self.formatting == 'html':
66 sys.stdout.write('</table>'+'\n')
67 elif self.formatting == 'wiki':
68 sys.stdout.write('|}'+'\n')
74 def start_suite(self, suite):
75 """Called when suite starts.
77 :param suite: Suite to process.
82 level = len(suite.longname.split("."))
84 if self.formatting == 'html':
85 mark_l = '<h'+str(level)+'>'
86 mark_r = '</h'+str(level)+'>'
87 sys.stdout.write(mark_l+suite.name+mark_r+'\n')
88 sys.stdout.write('<p>'+re.sub(r"(\*)(.*?)(\*)", r"<b>\2</b>",\
89 suite.doc, 0, flags=re.MULTILINE).replace(\
90 '[', '<br>[')+'</p>\n')
92 elif self.formatting == 'wiki':
93 mark = "=" * (level+2)
94 sys.stdout.write(mark+suite.name+mark+'\n')
95 sys.stdout.write(re.sub(r"(\*)(.*?)(\*)", r"\n*'''\2'''",\
96 suite.doc.replace('\n', ' '), 0, flags=re.MULTILINE)+'\n')
100 def end_suite(self, suite):
101 """Called when suite ends.
103 :param suite: Suite to process.
110 def visit_test(self, test):
111 """Implements traversing through the test.
113 :param test: Test to process.
118 if self.start_test(test) is not False:
121 def start_test(self, test):
122 """Called when test starts.
124 :param test: Test to process.
129 if self.formatting == 'html':
130 sys.stdout.write('<tr>'+'\n')
131 sys.stdout.write('<td>'+test.name+'</td>'+'\n')
132 sys.stdout.write('<td>'+test.doc+'</td>'+'\n')
133 if any("PERFTEST_LONG" in tag for tag in test.tags):
134 sys.stdout.write('<td>'+test.message+'</td>'+'\n')
135 sys.stdout.write('<td>'+test.status+'</td>'+'\n')
136 elif self.formatting == 'wiki':
137 sys.stdout.write('|-'+'\n')
138 sys.stdout.write('|'+test.name+'\n')
139 sys.stdout.write('|'+test.doc.replace('\n', ' ').replace('\r',\
141 if any("PERFTEST_LONG" in tag for tag in test.tags):
142 sys.stdout.write('|'+test.message+'\n')
143 sys.stdout.write('|'+test.status+'\n')
147 def end_test(self, test):
148 """Called when test ends.
150 :param test: Test to process.
155 if self.formatting == 'html':
156 sys.stdout.write('</tr>'+'\n')
157 elif self.formatting == 'wiki':
163 def process_robot_file(args):
164 """Process data from robot output.xml file and return raw data.
166 :param args: Parsed arguments.
167 :type args: ArgumentParser
171 result = ExecutionResult(args.input)
172 checker = ExecutionChecker(args)
173 result.visit(checker)
176 def print_error(msg):
177 """Print error message on stderr.
179 :param msg: Error message to print.
184 sys.stderr.write(msg+'\n')
188 """Parse arguments from cmd line.
190 :return: Parsed arguments.
191 :rtype ArgumentParser
194 parser = argparse.ArgumentParser()
195 parser.add_argument("-i", "--input", required=True,
196 type=argparse.FileType('r'),
197 help="Robot XML log file")
198 parser.add_argument("-o", "--output",
199 type=argparse.FileType('w'),
201 parser.add_argument("-f", "--formatting", required=True,
202 choices=['html', 'wiki'],
203 help="Output file format")
205 return parser.parse_args()
214 sys.stdout = args.output
216 process_robot_file(args)
219 if __name__ == "__main__":