2 ##########################################################################
4 # Copyright 2009 VMware, Inc.
5 # Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
8 # Permission is hereby granted, free of charge, to any person obtaining a
9 # copy of this software and associated documentation files (the
10 # "Software"), to deal in the Software without restriction, including
11 # without limitation the rights to use, copy, modify, merge, publish,
12 # distribute, sub license, and/or sell copies of the Software, and to
13 # permit persons to whom the Software is furnished to do so, subject to
14 # the following conditions:
16 # The above copyright notice and this permission notice (including the
17 # next paragraph) shall be included in all copies or substantial portions
20 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
23 # IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
24 # ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 ##########################################################################
31 """Base classes for tests.
33 Loosely inspired on Python's unittest module.
43 # Enumerate all pixel formats
45 for name
, value
in globals().items():
46 if name
.startswith("PIPE_FORMAT_") and isinstance(value
, int) and name
not in ("PIPE_FORMAT_NONE", "PIPE_FORMAT_COUNT"):
49 def make_image(width
, height
, rgba
):
55 outpixels
= outimage
.load()
56 for y
in range(0, height
):
57 for x
in range(0, width
):
58 offset
= (y
*width
+ x
)*4
59 r
, g
, b
, a
= [int(min(max(rgba
[offset
+ ch
], 0.0), 1.0)*255) for ch
in range(4)]
60 outpixels
[x
, y
] = r
, g
, b
63 def save_image(width
, height
, rgba
, filename
):
64 outimage
= make_image(width
, height
, rgba
)
65 outimage
.save(filename
, "PNG")
67 def show_image(width
, height
, **rgbas
):
69 from PIL
import Image
, ImageTk
78 for i
in range(len(labels
)):
80 outimage
= make_image(width
, height
, rgbas
[label
])
83 window
= tk
.Toplevel(root
)
87 image1
= ImageTk
.PhotoImage(outimage
)
90 window
.geometry("%dx%d+%d+%d" % (w
, h
, x
, y
))
91 panel1
= tk
.Label(window
, image
=image1
)
92 panel1
.pack(side
='top', fill
='both', expand
='yes')
99 class TestFailure(Exception):
103 class TestSkip(Exception):
113 def _run(self
, result
):
114 raise NotImplementedError
117 result
= TestResult()
121 def assert_rgba(self
, ctx
, surface
, x
, y
, w
, h
, expected_rgba
, pixel_tol
=4.0/256, surface_tol
=0.85):
123 different
= ctx
.surface_compare_rgba(surface
, x
, y
, w
, h
, expected_rgba
, tol
=pixel_tol
)
125 sys
.stderr
.write("%u out of %u pixels differ\n" % (different
, total
))
127 if float(total
- different
)/float(total
) < surface_tol
:
129 rgba
= FloatArray(h
*w
*4)
130 ctx
.surface_read_rgba(surface
, x
, y
, w
, h
, rgba
)
131 show_image(w
, h
, Result
=rgba
, Expected
=expected_rgba
)
132 save_image(w
, h
, rgba
, "result.png")
133 save_image(w
, h
, expected_rgba
, "expected.png")
139 class TestCase(Test
):
143 def __init__(self
, dev
, **kargs
):
146 self
.__dict
__.update(kargs
)
148 def description(self
):
150 for tag
in self
.tags
:
151 value
= self
.get(tag
)
152 if value
is not None and value
!= '':
153 descriptions
.append(tag
+ '=' + str(value
))
154 return ' '.join(descriptions
)
158 method
= getattr(self
, '_get_' + tag
)
159 except AttributeError:
160 return getattr(self
, tag
, None)
164 def _get_target(self
):
166 PIPE_TEXTURE_1D
: "1d",
167 PIPE_TEXTURE_2D
: "2d",
168 PIPE_TEXTURE_3D
: "3d",
169 PIPE_TEXTURE_CUBE
: "cube",
172 def _get_format(self
):
173 name
= formats
[self
.format
]
174 if name
.startswith('PIPE_FORMAT_'):
180 if self
.target
== PIPE_TEXTURE_CUBE
:
182 PIPE_TEX_FACE_POS_X
: "+x",
183 PIPE_TEX_FACE_NEG_X
: "-x",
184 PIPE_TEX_FACE_POS_Y
: "+y",
185 PIPE_TEX_FACE_NEG_Y
: "-y",
186 PIPE_TEX_FACE_POS_Z
: "+z",
187 PIPE_TEX_FACE_NEG_Z
: "-z",
193 raise NotImplementedError
195 def _run(self
, result
):
196 result
.test_start(self
)
199 except KeyboardInterrupt:
202 result
.test_skipped(self
)
204 result
.test_failed(self
)
206 result
.test_passed(self
)
209 class TestSuite(Test
):
211 def __init__(self
, tests
= None):
218 def add_test(self
, test
):
219 self
.tests
.append(test
)
221 def _run(self
, result
):
222 for test
in self
.tests
:
234 self
.names
= ['result']
235 self
.types
= ['pass skip fail']
238 def test_start(self
, test
):
239 sys
.stdout
.write("Running %s...\n" % test
.description())
243 def test_passed(self
, test
):
244 sys
.stdout
.write("PASS\n")
247 self
.log_result(test
, 'pass')
249 def test_skipped(self
, test
):
250 sys
.stdout
.write("SKIP\n")
253 self
.log_result(test
, 'skip')
255 def test_failed(self
, test
):
256 sys
.stdout
.write("FAIL\n")
259 self
.log_result(test
, 'fail')
261 def log_result(self
, test
, result
):
262 row
= ['']*len(self
.names
)
265 assert self
.names
[0] == 'result'
266 assert result
in ('pass', 'skip', 'fail')
270 for tag
in test
.tags
:
271 value
= test
.get(tag
)
276 elif isinstance(value
, (int, float)):
278 type = 'c' # continous
279 elif isinstance(value
, basestring
):
280 type = 'd' # discrete
284 type = 'd' # discrete
288 col
= self
.names
.index(tag
, 1)
290 self
.names
.append(tag
)
291 self
.types
.append(type)
295 assert self
.types
[col
] == type
297 self
.rows
.append(row
)
300 sys
.stdout
.write("%u tests, %u passed, %u skipped, %u failed\n\n" % (self
.tests
, self
.passed
, self
.skipped
, self
.failed
))
303 name
, ext
= os
.path
.splitext(os
.path
.basename(sys
.argv
[0]))
305 tree
= self
.report_tree(name
)
306 self
.report_junit(name
, stdout
=tree
)
308 def report_tree(self
, name
):
309 filename
= name
+ '.tsv'
310 stream
= file(filename
, 'wt')
313 stream
.write('\t'.join(self
.names
) + '\n')
314 stream
.write('\t'.join(self
.types
) + '\n')
315 stream
.write('class\n')
318 for row
in self
.rows
:
321 row
+= ['']*(len(self
.names
) - len(row
))
322 stream
.write('\t'.join(row
) + '\n')
326 # See http://www.ailab.si/orange/doc/ofb/c_otherclass.htm
331 sys
.stderr
.write('Install Orange from http://www.ailab.si/orange/ for a classification tree.\n')
334 data
= orange
.ExampleTable(filename
)
336 tree
= orngTree
.TreeLearner(data
, sameMajorityPruning
=1, mForPruning
=2)
338 orngTree
.printTxt(tree
, maxDepth
=4)
340 text_tree
= orngTree
.dumpTree(tree
)
342 file(name
+ '.txt', 'wt').write(text_tree
)
344 orngTree
.printDot(tree
, fileName
=name
+'.dot', nodeShape
='ellipse', leafShape
='box')
348 def report_junit(self
, name
, stdout
=None, stderr
=None):
349 """Write test results in ANT's junit XML format, to use with Hudson CI.
352 - http://fisheye.hudson-ci.org/browse/Hudson/trunk/hudson/main/core/src/test/resources/hudson/tasks/junit
353 - http://www.junit.org/node/399
354 - http://wiki.apache.org/ant/Proposals/EnhancedTestReports
357 stream
= file(name
+ '.xml', 'wt')
359 stream
.write('<?xml version="1.0" encoding="UTF-8" ?>\n')
360 stream
.write('<testsuite name="%s">\n' % self
.escape_xml(name
))
361 stream
.write(' <properties>\n')
362 stream
.write(' </properties>\n')
364 names
= self
.names
[1:]
366 for row
in self
.rows
:
368 test_name
= ' '.join(['%s=%s' % pair
for pair
in zip(self
.names
[1:], row
[1:])])
370 stream
.write(' <testcase name="%s">\n' % (self
.escape_xml(test_name
)))
375 elif result
== 'skip':
376 stream
.write(' <skipped/>\n')
378 stream
.write(' <failure/>\n')
380 stream
.write(' </testcase>\n')
383 stream
.write(' <system-out>%s</system-out>\n' % self
.escape_xml(stdout
))
385 stream
.write(' <system-err>%s</system-err>\n' % self
.escape_xml(stderr
))
387 stream
.write('</testsuite>\n')
391 def escape_xml(self
, s
):
392 '''Escape a XML string.'''
393 s
= s
.replace('&', '&')
394 s
= s
.replace('<', '<')
395 s
= s
.replace('>', '>')
396 s
= s
.replace('"', '"')
397 s
= s
.replace("'", ''')