3 # Permission is hereby granted, free of charge, to any person
4 # obtaining a copy of this software and associated documentation
5 # files (the "Software"), to deal in the Software without
6 # restriction, including without limitation the rights to use,
7 # copy, modify, merge, publish, distribute, sublicense, and/or
8 # sell copies of the Software, and to permit persons to whom the
9 # Software is furnished to do so, subject to the following
12 # This permission notice shall be included in all copies or
13 # substantial portions of the Software.
15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
16 # KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
17 # WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
18 # PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR(S) BE
19 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
20 # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
21 # OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 # DEALINGS IN THE SOFTWARE.
24 from getopt
import getopt
, GetoptError
29 import framework
.core
as core
30 import framework
.summary
33 #############################################################################
34 ##### Auxiliary functions
35 #############################################################################
37 def testPathToHtmlFilename(path
):
38 return 'test_' + filter(lambda s
: s
.isalnum() or s
== '_', path
.replace('/', '__')) + '.html'
41 #############################################################################
43 #############################################################################
45 def readfile(filename
):
46 f
= open(filename
, "r")
51 def writefile(filename
, text
):
52 f
= open(filename
, "w")
56 templatedir
= os
.path
.join(os
.path
.dirname(__file__
), 'templates')
57 Result
= readfile(os
.path
.join(templatedir
, 'result.html'))
58 ResultDetail
= readfile(os
.path
.join(templatedir
, 'result_detail.html'))
59 ResultList
= readfile(os
.path
.join(templatedir
, 'result_list.html'))
60 ResultListItem
= readfile(os
.path
.join(templatedir
, 'result_listitem.html'))
61 ResultMString
= readfile(os
.path
.join(templatedir
, 'result_mstring.html'))
63 Index
= readfile(os
.path
.join(templatedir
, 'index.html'))
64 IndexTestrun
= readfile(os
.path
.join(templatedir
, 'index_testrun.html'))
65 IndexTestrunB
= readfile(os
.path
.join(templatedir
, 'index_testrunb.html'))
66 IndexTestrunBHref
= readfile(os
.path
.join(templatedir
, 'index_testrunb_href.html'))
67 IndexGroup
= readfile(os
.path
.join(templatedir
, 'index_group.html'))
68 IndexGroupTestrun
= readfile(os
.path
.join(templatedir
, 'index_group_testrun.html'))
69 IndexGroupGroup
= readfile(os
.path
.join(templatedir
, 'index_groupgroup.html'))
70 IndexTest
= readfile(os
.path
.join(templatedir
, 'index_test.html'))
71 IndexTestTestrun
= readfile(os
.path
.join(templatedir
, 'index_test_testrun.html'))
73 Testrun
= readfile(os
.path
.join(templatedir
, 'testrun.html'))
77 'changes': 'changes.html',
78 'problems': 'problems.html'
81 def buildDetailValue(detail
):
82 if type(detail
) == list:
86 items
= items
+ ResultListItem
% { 'detail': buildDetailValue(d
) }
88 return ResultList
% { 'items': items
}
89 elif type(detail
) == str and detail
[0:3] == '@@@':
90 return ResultMString
% { 'detail': cgi
.escape(detail
[3:]) }
92 return cgi
.escape(str(detail
))
95 def buildDetails(testResult
):
97 for name
in testResult
:
98 if type(name
) != str or name
== 'result':
101 value
= buildDetailValue(testResult
[name
])
102 details
+= [(name
, value
)]
104 details
.sort(lambda a
, b
: len(a
[1])-len(b
[1]))
108 for name
, value
in details
:
109 text
+= ResultDetail
% locals()
119 def writeResultHtml(test
, testResult
, filename
):
122 status
= testResult
.status
124 if 'result' in testResult
:
125 result
= testResult
['result']
129 details
= buildDetails(testResult
)
131 writefile(filename
, Result
% locals())
133 def writeTestrunHtml(testrun
, filename
):
134 detaildict
= dict(filter(lambda item
: item
[0] in testrun
.globalkeys
, testrun
.__dict
__.items()))
135 details
= buildDetails(detaildict
)
137 codename
= testrun
.codename
139 writefile(filename
, Testrun
% locals())
141 def buildTestSummary(indent
, alternate
, testsummary
):
142 tenindent
= 10 - indent
143 path
= testsummary
.path
144 name
= testsummary
.name
145 testruns
= "".join([IndexTestTestrun
% {
146 'alternate': alternate
,
147 'status': result
.status
,
148 'link': result
.testrun
.codename
+ '/' + testPathToHtmlFilename(path
)
149 } for result
in testsummary
.results
])
151 return IndexTest
% locals()
154 def buildGroupSummaryTestrun(groupresult
):
155 passnr
= groupresult
.passvector
.passnr
156 warnnr
= groupresult
.passvector
.warnnr
157 failnr
= groupresult
.passvector
.failnr
158 skipnr
= groupresult
.passvector
.skipnr
159 totalnr
= passnr
+ warnnr
+ failnr
# do not count skips
170 return IndexGroupTestrun
% locals()
173 def buildGroupSummary(indent
, groupsummary
, showcurrent
):
174 tenindent
= 10 - indent
178 path
= groupsummary
.path
179 name
= groupsummary
.name
180 names
= groupsummary
.children
.keys()
182 if showcurrent
== 'changes':
183 names
= filter(lambda n
: groupsummary
.children
[n
].changes
, names
)
184 elif showcurrent
== 'problems':
185 names
= filter(lambda n
: groupsummary
.children
[n
].problems
, names
)
189 child
= groupsummary
.children
[n
]
190 if isinstance(child
, framework
.summary
.GroupSummary
):
191 items
= items
+ IndexGroupGroup
% {
192 'group': buildGroupSummary(indent
+1, child
, showcurrent
)
195 items
= items
+ buildTestSummary(indent
+1, alternate
, child
)
202 testruns
= "".join([buildGroupSummaryTestrun(result
)
203 for result
in groupsummary
.results
])
205 return IndexGroup
% locals()
208 def writeSummaryHtml(summary
, summaryDir
, showcurrent
):
210 results is an array containing the top-level results dictionarys.
213 if to
== showcurrent
:
216 page
= SummaryPages
[to
]
217 return '<a href="%(page)s">%(to)s</a>' % locals()
220 if 'href' in tr
.__dict
__:
221 return IndexTestrunBHref
% tr
.__dict
__
223 return IndexTestrunB
% tr
.__dict
__
225 group
= buildGroupSummary(1, summary
.root
, showcurrent
)
226 testruns
= "".join([IndexTestrun
% tr
.__dict
__ for tr
in summary
.testruns
])
227 testrunsb
= "".join([testrunb(tr
) for tr
in summary
.testruns
])
229 tolist
= SummaryPages
.keys()
231 showlinks
= " | ".join([link(to
) for to
in tolist
])
233 writefile(summaryDir
+ '/' + SummaryPages
[showcurrent
], Index
% locals())
236 #############################################################################
238 #############################################################################
241 Usage: %(progName)s [options] [summary-dir] [test.results]...
244 -f, --full Prefer the full results over the
245 -h, --help Show this message
246 -o, --overwrite Overwrite existing directories
247 -l, --list=listfile Use test results from a list file
250 %(progName)s summary/mysum results/all.results
254 [ 'test.result', { name: 'override-name' } ],
258 print USAGE
% {'progName': sys
.argv
[0]}
262 def parse_listfile(filename
):
263 file = open(filename
, "r")
264 code
= "".join([s
for s
in file])
268 def loadresult(descr
, OptionPreferSummary
):
269 result
= core
.loadTestResults(descr
[0], OptionPreferSummary
)
271 result
.__dict
__.update(descr
[1])
276 options
, args
= getopt(sys
.argv
[1:], "hofl:", [ "help", "overwrite", "full", "list" ])
280 OptionOverwrite
= False
281 OptionPreferSummary
= True
283 for name
, value
in options
:
284 if name
== "-h" or name
== "--help":
286 elif name
== "-o" or name
== "--overwrite":
287 OptionOverwrite
= True
288 elif name
== "-f" or name
== "--full":
289 OptionPreferSummary
= False
290 elif name
== "-l" or name
== "--list":
291 OptionList
+= parse_listfile(value
)
293 OptionList
+= [[name
] for name
in args
[1:]]
295 if len(args
) < 1 or len(OptionList
) == 0:
299 core
.checkDir(summaryDir
, not OptionOverwrite
)
301 results
= [loadresult(descr
, OptionPreferSummary
) for descr
in OptionList
]
303 summary
= framework
.summary
.Summary(results
)
304 for j
in range(len(summary
.testruns
)):
305 tr
= summary
.testruns
[j
]
306 tr
.codename
= filter(lambda s
: s
.isalnum(), tr
.name
)
307 dirname
= summaryDir
+ '/' + tr
.codename
308 core
.checkDir(dirname
, False)
309 writeTestrunHtml(tr
, dirname
+ '/index.html')
310 for test
in summary
.allTests():
311 filename
= dirname
+ '/' + testPathToHtmlFilename(test
.path
)
312 writeResultHtml(test
, test
.results
[j
], filename
)
314 writefile(os
.path
.join(summaryDir
, 'result.css'), readfile(os
.path
.join(templatedir
, 'result.css')))
315 writefile(os
.path
.join(summaryDir
, 'index.css'), readfile(os
.path
.join(templatedir
, 'index.css')))
316 writeSummaryHtml(summary
, summaryDir
, 'all')
317 writeSummaryHtml(summary
, summaryDir
, 'problems')
318 writeSummaryHtml(summary
, summaryDir
, 'changes')
321 if __name__
== "__main__":