VirtualBox

source: vbox/trunk/src/VBox/ValidationKit/analysis/reporting.py@ 79723

Last change on this file since 79723 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1# -*- coding: utf-8 -*-
2# $Id: reporting.py 76553 2019-01-01 01:45:53Z vboxsync $
3
4"""
5Test Result Report Writer.
6
7This takes a processed test result tree and creates a HTML, re-structured text,
8or normal text report from it.
9"""
10
11__copyright__ = \
12"""
13Copyright (C) 2010-2019 Oracle Corporation
14
15This file is part of VirtualBox Open Source Edition (OSE), as
16available from http://www.virtualbox.org. This file is free software;
17you can redistribute it and/or modify it under the terms of the GNU
18General Public License (GPL) as published by the Free Software
19Foundation, in version 2 as it comes in the "COPYING" file of the
20VirtualBox OSE distribution. VirtualBox OSE is distributed in the
21hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
22
23The contents of this file may alternatively be used under the terms
24of the Common Development and Distribution License Version 1.0
25(CDDL) only, as it comes in the "COPYING.CDDL" file of the
26VirtualBox OSE distribution, in which case the provisions of the
27CDDL are applicable instead of those of the GPL.
28
29You may elect to license modified versions of this file under the
30terms and conditions of either the GPL or the CDDL or both.
31"""
32__version__ = "$Revision: 76553 $"
33__all__ = ['HtmlReport', 'RstReport', 'TextReport'];
34
35
36def tryAddThousandSeparators(sPotentialInterger):
37 """ Apparently, python 3.0(/3.1) has(/will have) support for this..."""
38 # Try convert the string/value to a long.
39 try:
40 lVal = long(sPotentialInterger);
41 lVal = long(sPotentialInterger);
42 except:
43 return sPotentialInterger;
44
45 # Convert it back to a string (paranoia) and build up the new string.
46 sOld = str(lVal);
47 chSign = '';
48 if sOld[0] == '-':
49 chSign = '-';
50 sOld = sOld[1:];
51 elif sPotentialInterger[0] == '+':
52 chSign = '+';
53 cchDigits = len(sOld);
54 iDigit = 0
55 sNewVal = '';
56 while iDigit < cchDigits:
57 if (iDigit % 3) == 0 and iDigit > 0:
58 sNewVal = ' ' + sNewVal;
59 sNewVal = sOld[cchDigits - iDigit - 1] + sNewVal;
60 iDigit += 1;
61 return chSign + sNewVal;
62
63
64class Table(object):
65 """
66 A table as a header as well as data rows, thus this class.
67 """
68 def __init__(self, oTest, fSplitDiff):
69 self.aasRows = [];
70 self.asHeader = ['Test',];
71 self.asUnits = ['',];
72 for oValue in oTest.aoValues:
73 self.asHeader.append(oValue.sName);
74 self.asUnits.append(oValue.sUnit);
75 self.addRow(oTest, fSplitDiff);
76
77 def addRow(self, oTest, fSplitDiff):
78 """Adds a row."""
79 asRow = [oTest.getFullName(),];
80 for oValue in oTest.aoValues:
81 asRow.append(oValue.sValue);
82 if not fSplitDiff:
83 self.aasRows.append(asRow);
84 else:
85 # Split cells into multiple rows on '|'. Omit the first column.
86 iRow = 0;
87 asThisRow = [asRow[0], ];
88 fMoreTodo = True;
89 while fMoreTodo:
90 for i in range(1, len(asRow)):
91 asSplit = asRow[i].split('|');
92 asThisRow.append(asSplit[0]);
93 asRow[i] = '|'.join(asSplit[1:])
94 self.aasRows.append(asThisRow);
95
96 # Done?
97 fMoreTodo = False;
98 for i in range(1, len(asRow)):
99 if len(asRow[i]):
100 fMoreTodo = True;
101 asThisRow = ['', ];
102 iRow += 1;
103
104 # Readability hack: Add an extra row if there are diffs.
105 if iRow > 1:
106 asRow[0] = '';
107 self.aasRows.append(asRow);
108
109 return True;
110
111 def hasTheSameHeadingAsTest(self, oTest):
112 """ Checks if the test values has the same heading."""
113 i = 1;
114 for oValue in oTest.aoValues:
115 if self.asHeader[i] != oValue.sName:
116 return False;
117 if self.asUnits[i] != oValue.sUnit:
118 return False;
119 i += 1;
120 return True;
121
122 def hasTheSameHeadingAsTable(self, oTable):
123 """ Checks if the other table has the same heading."""
124 if len(oTable.asHeader) != len(self.asHeader):
125 return False;
126 for i in range(len(self.asHeader)):
127 if self.asHeader[i] != oTable.asHeader[i]:
128 return False;
129 if self.asUnits[i] != oTable.asUnits[i]:
130 return False;
131 return True;
132
133 def appendTable(self, oTable):
134 """ Append the rows in oTable. oTable has the same heading as us. """
135 self.aasRows.extend(oTable.aasRows);
136 return True;
137
138 # manipulation and stuff
139
140 def optimizeUnit(self):
141 """ Turns bytes into KB, MB or GB. """
142 ## @todo
143 pass;
144
145 def addThousandSeparators(self):
146 """ Adds thousand separators to make numbers more readable. """
147 for iRow in range(len(self.aasRows)):
148 for iColumn in range(1, len(self.aasRows[iRow])):
149 asValues = self.aasRows[iRow][iColumn].split('|');
150 for i in range(len(asValues)):
151 asValues[i] = tryAddThousandSeparators(asValues[i]);
152 self.aasRows[iRow][iColumn] = '|'.join(asValues);
153 return True;
154
155 def getRowWidths(self):
156 """Figure out the column withs."""
157 # Header is first.
158 acchColumns = [];
159 for i in range(len(self.asHeader)):
160 cch = 1;
161 asWords = self.asHeader[i].split();
162 for s in asWords:
163 if len(s) > cch:
164 cch = len(s);
165 if i > 0 and len(self.asUnits[i]) > cch:
166 cch = len(self.asUnits[i]);
167 acchColumns.append(cch);
168
169 # Check out all cells.
170 for asColumns in self.aasRows:
171 for i in range(len(asColumns)):
172 if len(asColumns[i]) > acchColumns[i]:
173 acchColumns[i] = len(asColumns[i]);
174 return acchColumns;
175
176
177def tabelizeTestResults(oTest, fSplitDiff):
178 """
179 Break the test results down into a list of tables containing the values.
180
181 TODO: Handle passed / failed stuff too. Not important for benchmarks.
182 """
183 # Pass 1
184 aoTables = [];
185 aoStack = [];
186 aoStack.append((oTest, 0));
187 while len(aoStack) > 0:
188 oCurTest, iChild = aoStack.pop();
189
190 # depth first
191 if iChild < len(oCurTest.aoChildren):
192 aoStack.append((oCurTest, iChild + 1));
193 aoStack.append((oCurTest.aoChildren[iChild], 0));
194 continue;
195
196 # values -> row
197 if len(oCurTest.aoValues) > 0:
198 if len(aoTables) > 0 and aoTables[len(aoTables) - 1].hasTheSameHeadingAsTest(oCurTest):
199 aoTables[len(aoTables) - 1].addRow(oCurTest, fSplitDiff);
200 else:
201 aoTables.append(Table(oCurTest, fSplitDiff));
202
203 # Pass 2 - Combine tables with the same heading.
204 aoTables2 = [];
205 for oTable in aoTables:
206 for i in range(len(aoTables2)):
207 if aoTables2[i].hasTheSameHeadingAsTable(oTable):
208 aoTables2[i].appendTable(oTable);
209 oTable = None;
210 break;
211 if oTable is not None:
212 aoTables2.append(oTable);
213
214 return aoTables2;
215
216def produceHtmlReport(oTest):
217 """
218 Produce an HTML report on stdout (via print).
219 """
220 print 'not implemented: %s' % (oTest);
221 return False;
222
223def produceReStructuredTextReport(oTest):
224 """
225 Produce a ReStructured text report on stdout (via print).
226 """
227 print 'not implemented: %s' % (oTest);
228 return False;
229
230def produceTextReport(oTest):
231 """
232 Produce a text report on stdout (via print).
233 """
234
235 #
236 # Report header.
237 #
238 ## @todo later
239
240 #
241 # Tabelize the results and display the tables.
242 #
243 aoTables = tabelizeTestResults(oTest, True)
244 for oTable in aoTables:
245 ## @todo do max/min on the columns where we can do [GMK]B(/s).
246 oTable.addThousandSeparators();
247 acchColumns = oTable.getRowWidths();
248
249 # The header.
250 # This is a bit tedious and the solution isn't entirely elegant due
251 # to the pick-it-up-as-you-go-along python skills.
252 aasHeader = [];
253 aasHeader.append([]);
254 for i in range(len(oTable.asHeader)):
255 aasHeader[0].append('');
256
257 for iColumn in range(len(oTable.asHeader)):
258 asWords = oTable.asHeader[iColumn].split();
259 iLine = 0;
260 for s in asWords:
261 if len(aasHeader[iLine][iColumn]) <= 0:
262 aasHeader[iLine][iColumn] = s;
263 elif len(s) + 1 + len(aasHeader[iLine][iColumn]) <= acchColumns[iColumn]:
264 aasHeader[iLine][iColumn] += ' ' + s;
265 else:
266 iLine += 1;
267 if iLine >= len(aasHeader): # There must be a better way to do this...
268 aasHeader.append([]);
269 for i in range(len(oTable.asHeader)):
270 aasHeader[iLine].append('');
271 aasHeader[iLine][iColumn] = s;
272
273 for asLine in aasHeader:
274 sLine = '';
275 for i in range(len(asLine)):
276 if i > 0: sLine += ' ';
277 sLine += asLine[i].center(acchColumns[i]);
278 print sLine;
279
280 # Units.
281 sLine = '';
282 for i in range(len(oTable.asUnits)):
283 if i > 0: sLine += ' ';
284 sLine += oTable.asUnits[i].center(acchColumns[i]);
285 print sLine;
286
287 # Separator line.
288 sLine = '';
289 for i in range(len(oTable.asHeader)):
290 if i > 0: sLine += ' '
291 sLine += '=' * acchColumns[i];
292 print sLine;
293
294 # The rows.
295 for asColumns in oTable.aasRows:
296 sText = asColumns[0].ljust(acchColumns[0]);
297 for i in range(1, len(asColumns)):
298 sText += ' ' + asColumns[i].rjust(acchColumns[i]);
299 print sText;
300
301 return None;
302
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette