dg-extract-results.py revision 1.1.1.2 1 1.1 mrg #!/usr/bin/python
2 1.1 mrg #
3 1.1 mrg # Copyright (C) 2014 Free Software Foundation, Inc.
4 1.1 mrg #
5 1.1 mrg # This script is free software; you can redistribute it and/or modify
6 1.1 mrg # it under the terms of the GNU General Public License as published by
7 1.1 mrg # the Free Software Foundation; either version 3, or (at your option)
8 1.1 mrg # any later version.
9 1.1 mrg
10 1.1 mrg import sys
11 1.1 mrg import getopt
12 1.1 mrg import re
13 1.1 mrg import io
14 1.1 mrg from datetime import datetime
15 1.1 mrg from operator import attrgetter
16 1.1 mrg
17 1.1 mrg # True if unrecognised lines should cause a fatal error. Might want to turn
18 1.1 mrg # this on by default later.
19 1.1 mrg strict = False
20 1.1 mrg
21 1.1 mrg # True if the order of .log segments should match the .sum file, false if
22 1.1 mrg # they should keep the original order.
23 1.1 mrg sort_logs = True
24 1.1 mrg
25 1.1 mrg # A version of open() that is safe against whatever binary output
26 1.1 mrg # might be added to the log.
27 1.1 mrg def safe_open (filename):
28 1.1 mrg if sys.version_info >= (3, 0):
29 1.1 mrg return open (filename, 'r', errors = 'surrogateescape')
30 1.1 mrg return open (filename, 'r')
31 1.1 mrg
32 1.1 mrg # Force stdout to handle escape sequences from a safe_open file.
33 1.1 mrg if sys.version_info >= (3, 0):
34 1.1 mrg sys.stdout = io.TextIOWrapper (sys.stdout.buffer,
35 1.1 mrg errors = 'surrogateescape')
36 1.1 mrg
37 1.1 mrg class Named:
38 1.1 mrg def __init__ (self, name):
39 1.1 mrg self.name = name
40 1.1 mrg
41 1.1 mrg class ToolRun (Named):
42 1.1 mrg def __init__ (self, name):
43 1.1 mrg Named.__init__ (self, name)
44 1.1 mrg # The variations run for this tool, mapped by --target_board name.
45 1.1 mrg self.variations = dict()
46 1.1 mrg
47 1.1 mrg # Return the VariationRun for variation NAME.
48 1.1 mrg def get_variation (self, name):
49 1.1 mrg if name not in self.variations:
50 1.1 mrg self.variations[name] = VariationRun (name)
51 1.1 mrg return self.variations[name]
52 1.1 mrg
53 1.1 mrg class VariationRun (Named):
54 1.1 mrg def __init__ (self, name):
55 1.1 mrg Named.__init__ (self, name)
56 1.1 mrg # A segment of text before the harness runs start, describing which
57 1.1 mrg # baseboard files were loaded for the target.
58 1.1 mrg self.header = None
59 1.1 mrg # The harnesses run for this variation, mapped by filename.
60 1.1 mrg self.harnesses = dict()
61 1.1 mrg # A list giving the number of times each type of result has
62 1.1 mrg # been seen.
63 1.1 mrg self.counts = []
64 1.1 mrg
65 1.1 mrg # Return the HarnessRun for harness NAME.
66 1.1 mrg def get_harness (self, name):
67 1.1 mrg if name not in self.harnesses:
68 1.1 mrg self.harnesses[name] = HarnessRun (name)
69 1.1 mrg return self.harnesses[name]
70 1.1 mrg
71 1.1 mrg class HarnessRun (Named):
72 1.1 mrg def __init__ (self, name):
73 1.1 mrg Named.__init__ (self, name)
74 1.1 mrg # Segments of text that make up the harness run, mapped by a test-based
75 1.1 mrg # key that can be used to order them.
76 1.1 mrg self.segments = dict()
77 1.1 mrg # Segments of text that make up the harness run but which have
78 1.1 mrg # no recognized test results. These are typically harnesses that
79 1.1 mrg # are completely skipped for the target.
80 1.1 mrg self.empty = []
81 1.1 mrg # A list of results. Each entry is a pair in which the first element
82 1.1 mrg # is a unique sorting key and in which the second is the full
83 1.1 mrg # PASS/FAIL line.
84 1.1 mrg self.results = []
85 1.1 mrg
86 1.1 mrg # Add a segment of text to the harness run. If the segment includes
87 1.1 mrg # test results, KEY is an example of one of them, and can be used to
88 1.1 mrg # combine the individual segments in order. If the segment has no
89 1.1 mrg # test results (e.g. because the harness doesn't do anything for the
90 1.1 mrg # current configuration) then KEY is None instead. In that case
91 1.1 mrg # just collect the segments in the order that we see them.
92 1.1 mrg def add_segment (self, key, segment):
93 1.1 mrg if key:
94 1.1 mrg assert key not in self.segments
95 1.1 mrg self.segments[key] = segment
96 1.1 mrg else:
97 1.1 mrg self.empty.append (segment)
98 1.1 mrg
99 1.1 mrg class Segment:
100 1.1 mrg def __init__ (self, filename, start):
101 1.1 mrg self.filename = filename
102 1.1 mrg self.start = start
103 1.1 mrg self.lines = 0
104 1.1 mrg
105 1.1 mrg class Prog:
106 1.1 mrg def __init__ (self):
107 1.1 mrg # The variations specified on the command line.
108 1.1 mrg self.variations = []
109 1.1 mrg # The variations seen in the input files.
110 1.1 mrg self.known_variations = set()
111 1.1 mrg # The tools specified on the command line.
112 1.1 mrg self.tools = []
113 1.1 mrg # Whether to create .sum rather than .log output.
114 1.1 mrg self.do_sum = True
115 1.1 mrg # Regexps used while parsing.
116 1.1 mrg self.test_run_re = re.compile (r'^Test Run By (\S+) on (.*)$')
117 1.1 mrg self.tool_re = re.compile (r'^\t\t=== (.*) tests ===$')
118 1.1 mrg self.result_re = re.compile (r'^(PASS|XPASS|FAIL|XFAIL|UNRESOLVED'
119 1.1 mrg r'|WARNING|ERROR|UNSUPPORTED|UNTESTED'
120 1.1 mrg r'|KFAIL):\s*(.+)')
121 1.1 mrg self.completed_re = re.compile (r'.* completed at (.*)')
122 1.1 mrg # Pieces of text to write at the head of the output.
123 1.1 mrg # start_line is a pair in which the first element is a datetime
124 1.1 mrg # and in which the second is the associated 'Test Run By' line.
125 1.1 mrg self.start_line = None
126 1.1 mrg self.native_line = ''
127 1.1 mrg self.target_line = ''
128 1.1 mrg self.host_line = ''
129 1.1 mrg self.acats_premable = ''
130 1.1 mrg # Pieces of text to write at the end of the output.
131 1.1 mrg # end_line is like start_line but for the 'runtest completed' line.
132 1.1 mrg self.acats_failures = []
133 1.1 mrg self.version_output = ''
134 1.1 mrg self.end_line = None
135 1.1 mrg # Known summary types.
136 1.1 mrg self.count_names = [
137 1.1.1.2 mrg '# of DejaGnu errors\t\t',
138 1.1 mrg '# of expected passes\t\t',
139 1.1 mrg '# of unexpected failures\t',
140 1.1 mrg '# of unexpected successes\t',
141 1.1 mrg '# of expected failures\t\t',
142 1.1 mrg '# of unknown successes\t\t',
143 1.1 mrg '# of known failures\t\t',
144 1.1 mrg '# of untested testcases\t\t',
145 1.1 mrg '# of unresolved testcases\t',
146 1.1 mrg '# of unsupported tests\t\t'
147 1.1 mrg ]
148 1.1 mrg self.runs = dict()
149 1.1 mrg
150 1.1 mrg def usage (self):
151 1.1 mrg name = sys.argv[0]
152 1.1 mrg sys.stderr.write ('Usage: ' + name
153 1.1 mrg + ''' [-t tool] [-l variant-list] [-L] log-or-sum-file ...
154 1.1 mrg
155 1.1 mrg tool The tool (e.g. g++, libffi) for which to create a
156 1.1 mrg new test summary file. If not specified then output
157 1.1 mrg is created for all tools.
158 1.1 mrg variant-list One or more test variant names. If the list is
159 1.1 mrg not specified then one is constructed from all
160 1.1 mrg variants in the files for <tool>.
161 1.1 mrg sum-file A test summary file with the format of those
162 1.1 mrg created by runtest from DejaGnu.
163 1.1 mrg If -L is used, merge *.log files instead of *.sum. In this
164 1.1 mrg mode the exact order of lines may not be preserved, just different
165 1.1 mrg Running *.exp chunks should be in correct order.
166 1.1 mrg ''')
167 1.1 mrg sys.exit (1)
168 1.1 mrg
169 1.1 mrg def fatal (self, what, string):
170 1.1 mrg if not what:
171 1.1 mrg what = sys.argv[0]
172 1.1 mrg sys.stderr.write (what + ': ' + string + '\n')
173 1.1 mrg sys.exit (1)
174 1.1 mrg
175 1.1 mrg # Parse the command-line arguments.
176 1.1 mrg def parse_cmdline (self):
177 1.1 mrg try:
178 1.1 mrg (options, self.files) = getopt.getopt (sys.argv[1:], 'l:t:L')
179 1.1 mrg if len (self.files) == 0:
180 1.1 mrg self.usage()
181 1.1 mrg for (option, value) in options:
182 1.1 mrg if option == '-l':
183 1.1 mrg self.variations.append (value)
184 1.1 mrg elif option == '-t':
185 1.1 mrg self.tools.append (value)
186 1.1 mrg else:
187 1.1 mrg self.do_sum = False
188 1.1 mrg except getopt.GetoptError as e:
189 1.1 mrg self.fatal (None, e.msg)
190 1.1 mrg
191 1.1 mrg # Try to parse time string TIME, returning an arbitrary time on failure.
192 1.1 mrg # Getting this right is just a nice-to-have so failures should be silent.
193 1.1 mrg def parse_time (self, time):
194 1.1 mrg try:
195 1.1 mrg return datetime.strptime (time, '%c')
196 1.1 mrg except ValueError:
197 1.1 mrg return datetime.now()
198 1.1 mrg
199 1.1 mrg # Parse an integer and abort on failure.
200 1.1 mrg def parse_int (self, filename, value):
201 1.1 mrg try:
202 1.1 mrg return int (value)
203 1.1 mrg except ValueError:
204 1.1 mrg self.fatal (filename, 'expected an integer, got: ' + value)
205 1.1 mrg
206 1.1 mrg # Return a list that represents no test results.
207 1.1 mrg def zero_counts (self):
208 1.1 mrg return [0 for x in self.count_names]
209 1.1 mrg
210 1.1 mrg # Return the ToolRun for tool NAME.
211 1.1 mrg def get_tool (self, name):
212 1.1 mrg if name not in self.runs:
213 1.1 mrg self.runs[name] = ToolRun (name)
214 1.1 mrg return self.runs[name]
215 1.1 mrg
216 1.1 mrg # Add the result counts in list FROMC to TOC.
217 1.1 mrg def accumulate_counts (self, toc, fromc):
218 1.1 mrg for i in range (len (self.count_names)):
219 1.1 mrg toc[i] += fromc[i]
220 1.1 mrg
221 1.1 mrg # Parse the list of variations after 'Schedule of variations:'.
222 1.1 mrg # Return the number seen.
223 1.1 mrg def parse_variations (self, filename, file):
224 1.1 mrg num_variations = 0
225 1.1 mrg while True:
226 1.1 mrg line = file.readline()
227 1.1 mrg if line == '':
228 1.1 mrg self.fatal (filename, 'could not parse variation list')
229 1.1 mrg if line == '\n':
230 1.1 mrg break
231 1.1 mrg self.known_variations.add (line.strip())
232 1.1 mrg num_variations += 1
233 1.1 mrg return num_variations
234 1.1 mrg
235 1.1 mrg # Parse from the first line after 'Running target ...' to the end
236 1.1 mrg # of the run's summary.
237 1.1 mrg def parse_run (self, filename, file, tool, variation, num_variations):
238 1.1 mrg header = None
239 1.1 mrg harness = None
240 1.1 mrg segment = None
241 1.1 mrg final_using = 0
242 1.1 mrg
243 1.1 mrg # If this is the first run for this variation, add any text before
244 1.1 mrg # the first harness to the header.
245 1.1 mrg if not variation.header:
246 1.1 mrg segment = Segment (filename, file.tell())
247 1.1 mrg variation.header = segment
248 1.1 mrg
249 1.1.1.2 mrg # Parse the rest of the summary (the '# of ' lines).
250 1.1.1.2 mrg if len (variation.counts) == 0:
251 1.1.1.2 mrg variation.counts = self.zero_counts()
252 1.1.1.2 mrg
253 1.1 mrg # Parse up until the first line of the summary.
254 1.1 mrg if num_variations == 1:
255 1.1 mrg end = '\t\t=== ' + tool.name + ' Summary ===\n'
256 1.1 mrg else:
257 1.1 mrg end = ('\t\t=== ' + tool.name + ' Summary for '
258 1.1 mrg + variation.name + ' ===\n')
259 1.1 mrg while True:
260 1.1 mrg line = file.readline()
261 1.1 mrg if line == '':
262 1.1 mrg self.fatal (filename, 'no recognised summary line')
263 1.1 mrg if line == end:
264 1.1 mrg break
265 1.1 mrg
266 1.1 mrg # Look for the start of a new harness.
267 1.1 mrg if line.startswith ('Running ') and line.endswith (' ...\n'):
268 1.1 mrg # Close off the current harness segment, if any.
269 1.1 mrg if harness:
270 1.1 mrg segment.lines -= final_using
271 1.1 mrg harness.add_segment (first_key, segment)
272 1.1 mrg name = line[len ('Running '):-len(' ...\n')]
273 1.1 mrg harness = variation.get_harness (name)
274 1.1 mrg segment = Segment (filename, file.tell())
275 1.1 mrg first_key = None
276 1.1 mrg final_using = 0
277 1.1 mrg continue
278 1.1 mrg
279 1.1 mrg # Record test results. Associate the first test result with
280 1.1 mrg # the harness segment, so that if a run for a particular harness
281 1.1 mrg # has been split up, we can reassemble the individual segments
282 1.1 mrg # in a sensible order.
283 1.1 mrg #
284 1.1 mrg # dejagnu sometimes issues warnings about the testing environment
285 1.1 mrg # before running any tests. Treat them as part of the header
286 1.1 mrg # rather than as a test result.
287 1.1 mrg match = self.result_re.match (line)
288 1.1 mrg if match and (harness or not line.startswith ('WARNING:')):
289 1.1 mrg if not harness:
290 1.1 mrg self.fatal (filename, 'saw test result before harness name')
291 1.1 mrg name = match.group (2)
292 1.1 mrg # Ugly hack to get the right order for gfortran.
293 1.1 mrg if name.startswith ('gfortran.dg/g77/'):
294 1.1 mrg name = 'h' + name
295 1.1 mrg key = (name, len (harness.results))
296 1.1 mrg harness.results.append ((key, line))
297 1.1 mrg if not first_key and sort_logs:
298 1.1 mrg first_key = key
299 1.1.1.2 mrg if line.startswith ('ERROR: (DejaGnu)'):
300 1.1.1.2 mrg for i in range (len (self.count_names)):
301 1.1.1.2 mrg if 'DejaGnu errors' in self.count_names[i]:
302 1.1.1.2 mrg variation.counts[i] += 1
303 1.1.1.2 mrg break
304 1.1 mrg
305 1.1 mrg # 'Using ...' lines are only interesting in a header. Splitting
306 1.1 mrg # the test up into parallel runs leads to more 'Using ...' lines
307 1.1 mrg # than there would be in a single log.
308 1.1 mrg if line.startswith ('Using '):
309 1.1 mrg final_using += 1
310 1.1 mrg else:
311 1.1 mrg final_using = 0
312 1.1 mrg
313 1.1 mrg # Add other text to the current segment, if any.
314 1.1 mrg if segment:
315 1.1 mrg segment.lines += 1
316 1.1 mrg
317 1.1 mrg # Close off the final harness segment, if any.
318 1.1 mrg if harness:
319 1.1 mrg segment.lines -= final_using
320 1.1 mrg harness.add_segment (first_key, segment)
321 1.1 mrg
322 1.1 mrg while True:
323 1.1 mrg before = file.tell()
324 1.1 mrg line = file.readline()
325 1.1 mrg if line == '':
326 1.1 mrg break
327 1.1 mrg if line == '\n':
328 1.1 mrg continue
329 1.1 mrg if not line.startswith ('# '):
330 1.1 mrg file.seek (before)
331 1.1 mrg break
332 1.1 mrg found = False
333 1.1 mrg for i in range (len (self.count_names)):
334 1.1 mrg if line.startswith (self.count_names[i]):
335 1.1 mrg count = line[len (self.count_names[i]):-1].strip()
336 1.1 mrg variation.counts[i] += self.parse_int (filename, count)
337 1.1 mrg found = True
338 1.1 mrg break
339 1.1 mrg if not found:
340 1.1 mrg self.fatal (filename, 'unknown test result: ' + line[:-1])
341 1.1 mrg
342 1.1 mrg # Parse an acats run, which uses a different format from dejagnu.
343 1.1 mrg # We have just skipped over '=== acats configuration ==='.
344 1.1 mrg def parse_acats_run (self, filename, file):
345 1.1 mrg # Parse the preamble, which describes the configuration and logs
346 1.1 mrg # the creation of support files.
347 1.1 mrg record = (self.acats_premable == '')
348 1.1 mrg if record:
349 1.1 mrg self.acats_premable = '\t\t=== acats configuration ===\n'
350 1.1 mrg while True:
351 1.1 mrg line = file.readline()
352 1.1 mrg if line == '':
353 1.1 mrg self.fatal (filename, 'could not parse acats preamble')
354 1.1 mrg if line == '\t\t=== acats tests ===\n':
355 1.1 mrg break
356 1.1 mrg if record:
357 1.1 mrg self.acats_premable += line
358 1.1 mrg
359 1.1 mrg # Parse the test results themselves, using a dummy variation name.
360 1.1 mrg tool = self.get_tool ('acats')
361 1.1 mrg variation = tool.get_variation ('none')
362 1.1 mrg self.parse_run (filename, file, tool, variation, 1)
363 1.1 mrg
364 1.1 mrg # Parse the failure list.
365 1.1 mrg while True:
366 1.1 mrg before = file.tell()
367 1.1 mrg line = file.readline()
368 1.1 mrg if line.startswith ('*** FAILURES: '):
369 1.1 mrg self.acats_failures.append (line[len ('*** FAILURES: '):-1])
370 1.1 mrg continue
371 1.1 mrg file.seek (before)
372 1.1 mrg break
373 1.1 mrg
374 1.1 mrg # Parse the final summary at the end of a log in order to capture
375 1.1 mrg # the version output that follows it.
376 1.1 mrg def parse_final_summary (self, filename, file):
377 1.1 mrg record = (self.version_output == '')
378 1.1 mrg while True:
379 1.1 mrg line = file.readline()
380 1.1 mrg if line == '':
381 1.1 mrg break
382 1.1 mrg if line.startswith ('# of '):
383 1.1 mrg continue
384 1.1 mrg if record:
385 1.1 mrg self.version_output += line
386 1.1 mrg if line == '\n':
387 1.1 mrg break
388 1.1 mrg
389 1.1 mrg # Parse a .log or .sum file.
390 1.1 mrg def parse_file (self, filename, file):
391 1.1 mrg tool = None
392 1.1 mrg target = None
393 1.1 mrg num_variations = 1
394 1.1 mrg while True:
395 1.1 mrg line = file.readline()
396 1.1 mrg if line == '':
397 1.1 mrg return
398 1.1 mrg
399 1.1 mrg # Parse the list of variations, which comes before the test
400 1.1 mrg # runs themselves.
401 1.1 mrg if line.startswith ('Schedule of variations:'):
402 1.1 mrg num_variations = self.parse_variations (filename, file)
403 1.1 mrg continue
404 1.1 mrg
405 1.1 mrg # Parse a testsuite run for one tool/variation combination.
406 1.1 mrg if line.startswith ('Running target '):
407 1.1 mrg name = line[len ('Running target '):-1]
408 1.1 mrg if not tool:
409 1.1 mrg self.fatal (filename, 'could not parse tool name')
410 1.1 mrg if name not in self.known_variations:
411 1.1 mrg self.fatal (filename, 'unknown target: ' + name)
412 1.1 mrg self.parse_run (filename, file, tool,
413 1.1 mrg tool.get_variation (name),
414 1.1 mrg num_variations)
415 1.1 mrg # If there is only one variation then there is no separate
416 1.1 mrg # summary for it. Record any following version output.
417 1.1 mrg if num_variations == 1:
418 1.1 mrg self.parse_final_summary (filename, file)
419 1.1 mrg continue
420 1.1 mrg
421 1.1 mrg # Parse the start line. In the case where several files are being
422 1.1 mrg # parsed, pick the one with the earliest time.
423 1.1 mrg match = self.test_run_re.match (line)
424 1.1 mrg if match:
425 1.1 mrg time = self.parse_time (match.group (2))
426 1.1 mrg if not self.start_line or self.start_line[0] > time:
427 1.1 mrg self.start_line = (time, line)
428 1.1 mrg continue
429 1.1 mrg
430 1.1 mrg # Parse the form used for native testing.
431 1.1 mrg if line.startswith ('Native configuration is '):
432 1.1 mrg self.native_line = line
433 1.1 mrg continue
434 1.1 mrg
435 1.1 mrg # Parse the target triplet.
436 1.1 mrg if line.startswith ('Target is '):
437 1.1 mrg self.target_line = line
438 1.1 mrg continue
439 1.1 mrg
440 1.1 mrg # Parse the host triplet.
441 1.1 mrg if line.startswith ('Host is '):
442 1.1 mrg self.host_line = line
443 1.1 mrg continue
444 1.1 mrg
445 1.1 mrg # Parse the acats premable.
446 1.1 mrg if line == '\t\t=== acats configuration ===\n':
447 1.1 mrg self.parse_acats_run (filename, file)
448 1.1 mrg continue
449 1.1 mrg
450 1.1 mrg # Parse the tool name.
451 1.1 mrg match = self.tool_re.match (line)
452 1.1 mrg if match:
453 1.1 mrg tool = self.get_tool (match.group (1))
454 1.1 mrg continue
455 1.1 mrg
456 1.1 mrg # Skip over the final summary (which we instead create from
457 1.1 mrg # individual runs) and parse the version output.
458 1.1 mrg if tool and line == '\t\t=== ' + tool.name + ' Summary ===\n':
459 1.1 mrg if file.readline() != '\n':
460 1.1 mrg self.fatal (filename, 'expected blank line after summary')
461 1.1 mrg self.parse_final_summary (filename, file)
462 1.1 mrg continue
463 1.1 mrg
464 1.1 mrg # Parse the completion line. In the case where several files
465 1.1 mrg # are being parsed, pick the one with the latest time.
466 1.1 mrg match = self.completed_re.match (line)
467 1.1 mrg if match:
468 1.1 mrg time = self.parse_time (match.group (1))
469 1.1 mrg if not self.end_line or self.end_line[0] < time:
470 1.1 mrg self.end_line = (time, line)
471 1.1 mrg continue
472 1.1 mrg
473 1.1 mrg # Sanity check to make sure that important text doesn't get
474 1.1 mrg # dropped accidentally.
475 1.1 mrg if strict and line.strip() != '':
476 1.1 mrg self.fatal (filename, 'unrecognised line: ' + line[:-1])
477 1.1 mrg
478 1.1 mrg # Output a segment of text.
479 1.1 mrg def output_segment (self, segment):
480 1.1 mrg with safe_open (segment.filename) as file:
481 1.1 mrg file.seek (segment.start)
482 1.1 mrg for i in range (segment.lines):
483 1.1 mrg sys.stdout.write (file.readline())
484 1.1 mrg
485 1.1 mrg # Output a summary giving the number of times each type of result has
486 1.1 mrg # been seen.
487 1.1 mrg def output_summary (self, tool, counts):
488 1.1 mrg for i in range (len (self.count_names)):
489 1.1 mrg name = self.count_names[i]
490 1.1 mrg # dejagnu only prints result types that were seen at least once,
491 1.1 mrg # but acats always prints a number of unexpected failures.
492 1.1 mrg if (counts[i] > 0
493 1.1 mrg or (tool.name == 'acats'
494 1.1 mrg and name.startswith ('# of unexpected failures'))):
495 1.1 mrg sys.stdout.write ('%s%d\n' % (name, counts[i]))
496 1.1 mrg
497 1.1 mrg # Output unified .log or .sum information for a particular variation,
498 1.1 mrg # with a summary at the end.
499 1.1 mrg def output_variation (self, tool, variation):
500 1.1 mrg self.output_segment (variation.header)
501 1.1 mrg for harness in sorted (variation.harnesses.values(),
502 1.1 mrg key = attrgetter ('name')):
503 1.1 mrg sys.stdout.write ('Running ' + harness.name + ' ...\n')
504 1.1 mrg if self.do_sum:
505 1.1 mrg harness.results.sort()
506 1.1 mrg for (key, line) in harness.results:
507 1.1 mrg sys.stdout.write (line)
508 1.1 mrg else:
509 1.1 mrg # Rearrange the log segments into test order (but without
510 1.1 mrg # rearranging text within those segments).
511 1.1 mrg for key in sorted (harness.segments.keys()):
512 1.1 mrg self.output_segment (harness.segments[key])
513 1.1 mrg for segment in harness.empty:
514 1.1 mrg self.output_segment (segment)
515 1.1 mrg if len (self.variations) > 1:
516 1.1 mrg sys.stdout.write ('\t\t=== ' + tool.name + ' Summary for '
517 1.1 mrg + variation.name + ' ===\n\n')
518 1.1 mrg self.output_summary (tool, variation.counts)
519 1.1 mrg
520 1.1 mrg # Output unified .log or .sum information for a particular tool,
521 1.1 mrg # with a summary at the end.
522 1.1 mrg def output_tool (self, tool):
523 1.1 mrg counts = self.zero_counts()
524 1.1 mrg if tool.name == 'acats':
525 1.1 mrg # acats doesn't use variations, so just output everything.
526 1.1 mrg # It also has a different approach to whitespace.
527 1.1 mrg sys.stdout.write ('\t\t=== ' + tool.name + ' tests ===\n')
528 1.1 mrg for variation in tool.variations.values():
529 1.1 mrg self.output_variation (tool, variation)
530 1.1 mrg self.accumulate_counts (counts, variation.counts)
531 1.1 mrg sys.stdout.write ('\t\t=== ' + tool.name + ' Summary ===\n')
532 1.1 mrg else:
533 1.1 mrg # Output the results in the usual dejagnu runtest format.
534 1.1 mrg sys.stdout.write ('\n\t\t=== ' + tool.name + ' tests ===\n\n'
535 1.1 mrg 'Schedule of variations:\n')
536 1.1 mrg for name in self.variations:
537 1.1 mrg if name in tool.variations:
538 1.1 mrg sys.stdout.write (' ' + name + '\n')
539 1.1 mrg sys.stdout.write ('\n')
540 1.1 mrg for name in self.variations:
541 1.1 mrg if name in tool.variations:
542 1.1 mrg variation = tool.variations[name]
543 1.1 mrg sys.stdout.write ('Running target '
544 1.1 mrg + variation.name + '\n')
545 1.1 mrg self.output_variation (tool, variation)
546 1.1 mrg self.accumulate_counts (counts, variation.counts)
547 1.1 mrg sys.stdout.write ('\n\t\t=== ' + tool.name + ' Summary ===\n\n')
548 1.1 mrg self.output_summary (tool, counts)
549 1.1 mrg
550 1.1 mrg def main (self):
551 1.1 mrg self.parse_cmdline()
552 1.1 mrg try:
553 1.1 mrg # Parse the input files.
554 1.1 mrg for filename in self.files:
555 1.1 mrg with safe_open (filename) as file:
556 1.1 mrg self.parse_file (filename, file)
557 1.1 mrg
558 1.1 mrg # Decide what to output.
559 1.1 mrg if len (self.variations) == 0:
560 1.1 mrg self.variations = sorted (self.known_variations)
561 1.1 mrg else:
562 1.1 mrg for name in self.variations:
563 1.1 mrg if name not in self.known_variations:
564 1.1 mrg self.fatal (None, 'no results for ' + name)
565 1.1 mrg if len (self.tools) == 0:
566 1.1 mrg self.tools = sorted (self.runs.keys())
567 1.1 mrg
568 1.1 mrg # Output the header.
569 1.1 mrg if self.start_line:
570 1.1 mrg sys.stdout.write (self.start_line[1])
571 1.1 mrg sys.stdout.write (self.native_line)
572 1.1 mrg sys.stdout.write (self.target_line)
573 1.1 mrg sys.stdout.write (self.host_line)
574 1.1 mrg sys.stdout.write (self.acats_premable)
575 1.1 mrg
576 1.1 mrg # Output the main body.
577 1.1 mrg for name in self.tools:
578 1.1 mrg if name not in self.runs:
579 1.1 mrg self.fatal (None, 'no results for ' + name)
580 1.1 mrg self.output_tool (self.runs[name])
581 1.1 mrg
582 1.1 mrg # Output the footer.
583 1.1 mrg if len (self.acats_failures) > 0:
584 1.1 mrg sys.stdout.write ('*** FAILURES: '
585 1.1 mrg + ' '.join (self.acats_failures) + '\n')
586 1.1 mrg sys.stdout.write (self.version_output)
587 1.1 mrg if self.end_line:
588 1.1 mrg sys.stdout.write (self.end_line[1])
589 1.1 mrg except IOError as e:
590 1.1 mrg self.fatal (e.filename, e.strerror)
591 1.1 mrg
592 1.1 mrg Prog().main()
593