2 from xml.sax.saxutils import escape
6 class ResultCode(object):
7 """Test result codes."""
9 # We override __new__ and __getnewargs__ to ensure that pickling still
10 # provides unique ResultCode objects in any particular instance.
12 def __new__(cls, name, isFailure):
13 res = cls._instances.get(name)
15 cls._instances[name] = res = super(ResultCode, cls).__new__(cls)
17 def __getnewargs__(self):
18 return (self.name, self.isFailure)
20 def __init__(self, name, isFailure):
22 self.isFailure = isFailure
25 return '%s%r' % (self.__class__.__name__,
26 (self.name, self.isFailure))
28 PASS = ResultCode('PASS', False)
29 XFAIL = ResultCode('XFAIL', False)
30 FAIL = ResultCode('FAIL', True)
31 XPASS = ResultCode('XPASS', True)
32 UNRESOLVED = ResultCode('UNRESOLVED', True)
33 UNSUPPORTED = ResultCode('UNSUPPORTED', False)
37 class MetricValue(object):
42 Convert this metric to a string suitable for displaying as part of the
45 raise RuntimeError("abstract method")
49 todata() -> json-serializable data
51 Convert this metric to content suitable for serializing in the JSON test
54 raise RuntimeError("abstract method")
56 class IntMetricValue(MetricValue):
57 def __init__(self, value):
61 return str(self.value)
66 class RealMetricValue(MetricValue):
67 def __init__(self, value):
71 return '%.4f' % self.value
79 """Wrapper for the results of executing an individual test."""
81 def __init__(self, code, output='', elapsed=None):
86 # The wall timing to execute the test, if timing.
87 self.elapsed = elapsed
88 # The metrics reported by this test.
91 def addMetric(self, name, value):
93 addMetric(name, value)
95 Attach a test metric to the test result, with the given name and list of
96 values. It is an error to attempt to attach the metrics with the same
99 Each value must be an instance of a MetricValue subclass.
101 if name in self.metrics:
102 raise ValueError("result already includes metrics for %r" % (
104 if not isinstance(value, MetricValue):
105 raise TypeError("unexpected metric value: %r" % (value,))
106 self.metrics[name] = value
111 """TestSuite - Information on a group of tests.
113 A test suite groups together a set of logically related tests.
116 def __init__(self, name, source_root, exec_root, config):
118 self.source_root = source_root
119 self.exec_root = exec_root
120 # The test suite configuration.
123 def getSourcePath(self, components):
124 return os.path.join(self.source_root, *components)
126 def getExecPath(self, components):
127 return os.path.join(self.exec_root, *components)
130 """Test - Information on a single test instance."""
132 def __init__(self, suite, path_in_suite, config, file_path = None):
134 self.path_in_suite = path_in_suite
136 self.file_path = file_path
137 # A list of conditions under which this test is expected to fail. These
138 # can optionally be provided by test format handlers, and will be
139 # honored when the test result is supplied.
141 # The test result, once complete.
144 def setResult(self, result):
145 if self.result is not None:
146 raise ArgumentError("test result already set")
147 if not isinstance(result, Result):
148 raise ArgumentError("unexpected result type")
152 # Apply the XFAIL handling to resolve the result exit code.
153 if self.isExpectedToFail():
154 if self.result.code == PASS:
155 self.result.code = XPASS
156 elif self.result.code == FAIL:
157 self.result.code = XFAIL
159 def getFullName(self):
160 return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite)
162 def getFilePath(self):
164 return self.file_path
165 return self.getSourcePath()
167 def getSourcePath(self):
168 return self.suite.getSourcePath(self.path_in_suite)
170 def getExecPath(self):
171 return self.suite.getExecPath(self.path_in_suite)
173 def isExpectedToFail(self):
175 isExpectedToFail() -> bool
177 Check whether this test is expected to fail in the current
178 configuration. This check relies on the test xfails property which by
179 some test formats may not be computed until the test has first been
183 # Check if any of the xfails match an available feature or the target.
184 for item in self.xfails:
185 # If this is the wildcard, it always fails.
189 # If this is an exact match for one of the features, it fails.
190 if item in self.config.available_features:
193 # If this is a part of the target triple, it fails.
194 if item in self.suite.config.target_triple:
200 def getJUnitXML(self):
201 test_name = self.path_in_suite[-1]
202 test_path = self.path_in_suite[:-1]
203 safe_test_path = [x.replace(".","_") for x in test_path]
204 safe_name = self.suite.name.replace(".","-")
207 class_name = safe_name + "." + "/".join(safe_test_path)
209 class_name = safe_name + "." + safe_name
211 xml = "<testcase classname='" + class_name + "' name='" + \
213 xml += " time='%.2f'" % (self.result.elapsed,)
214 if self.result.code.isFailure:
215 xml += ">\n\t<failure >\n" + escape(self.result.output)
216 xml += "\n\t</failure>\n</testcase>"