d84eb4798f141e2d0e0cfd33d1813f3e2b104347
[oota-llvm.git] / utils / lit / lit / Test.py
1 import os
2
3 # Test result codes.
4
5 class ResultCode(object):
6     """Test result codes."""
7
8     # We override __new__ and __getnewargs__ to ensure that pickling still
9     # provides unique ResultCode objects in any particular instance.
10     _instances = {}
11     def __new__(cls, name, isFailure):
12         res = cls._instances.get(name)
13         if res is None:
14             cls._instances[name] = res = super(ResultCode, cls).__new__(cls)
15         return res
16     def __getnewargs__(self):
17         return (self.name, self.isFailure)
18
19     def __init__(self, name, isFailure):
20         self.name = name
21         self.isFailure = isFailure
22
23     def __repr__(self):
24         return '%s%r' % (self.__class__.__name__,
25                          (self.name, self.isFailure))
26
27 PASS        = ResultCode('PASS', False)
28 XFAIL       = ResultCode('XFAIL', False)
29 FAIL        = ResultCode('FAIL', True)
30 XPASS       = ResultCode('XPASS', True)
31 UNRESOLVED  = ResultCode('UNRESOLVED', True)
32 UNSUPPORTED = ResultCode('UNSUPPORTED', False)
33
34 # Test metric values.
35
36 class MetricValue(object):
37     def format(self):
38         raise RuntimeError("abstract method")
39
40 class IntMetricValue(MetricValue):
41     def __init__(self, value):
42         self.value = value
43
44     def format(self):
45         return str(self.value)
46
47 class RealMetricValue(MetricValue):
48     def __init__(self, value):
49         self.value = value
50
51     def format(self):
52         return '%.4f' % self.value
53
54 # Test results.
55
56 class Result(object):
57     """Wrapper for the results of executing an individual test."""
58
59     def __init__(self, code, output='', elapsed=None):
60         # The result code.
61         self.code = code
62         # The test output.
63         self.output = output
64         # The wall timing to execute the test, if timing.
65         self.elapsed = elapsed
66         # The metrics reported by this test.
67         self.metrics = {}
68
69     def addMetric(self, name, value):
70         """
71         addMetric(name, value)
72
73         Attach a test metric to the test result, with the given name and list of
74         values. It is an error to attempt to attach the metrics with the same
75         name multiple times.
76
77         Each value must be an instance of a MetricValue subclass.
78         """
79         if name in self.metrics:
80             raise ValueError("result already includes metrics for %r" % (
81                     name,))
82         if not isinstance(value, MetricValue):
83             raise TypeError("unexpected metric value: %r" % (value,))
84         self.metrics[name] = value
85
86 # Test classes.
87
88 class TestSuite:
89     """TestSuite - Information on a group of tests.
90
91     A test suite groups together a set of logically related tests.
92     """
93
94     def __init__(self, name, source_root, exec_root, config):
95         self.name = name
96         self.source_root = source_root
97         self.exec_root = exec_root
98         # The test suite configuration.
99         self.config = config
100
101     def getSourcePath(self, components):
102         return os.path.join(self.source_root, *components)
103
104     def getExecPath(self, components):
105         return os.path.join(self.exec_root, *components)
106
107 class Test:
108     """Test - Information on a single test instance."""
109
110     def __init__(self, suite, path_in_suite, config):
111         self.suite = suite
112         self.path_in_suite = path_in_suite
113         self.config = config
114         # A list of conditions under which this test is expected to fail. These
115         # can optionally be provided by test format handlers, and will be
116         # honored when the test result is supplied.
117         self.xfails = []
118         # The test result, once complete.
119         self.result = None
120
121     def setResult(self, result):
122         if self.result is not None:
123             raise ArgumentError("test result already set")
124         if not isinstance(result, Result):
125             raise ArgumentError("unexpected result type")
126
127         self.result = result
128
129         # Apply the XFAIL handling to resolve the result exit code.
130         if self.isExpectedToFail():
131             if self.result.code == PASS:
132                 self.result.code = XPASS
133             elif self.result.code == FAIL:
134                 self.result.code = XFAIL
135         
136     def getFullName(self):
137         return self.suite.config.name + ' :: ' + '/'.join(self.path_in_suite)
138
139     def getSourcePath(self):
140         return self.suite.getSourcePath(self.path_in_suite)
141
142     def getExecPath(self):
143         return self.suite.getExecPath(self.path_in_suite)
144
145     def isExpectedToFail(self):
146         """
147         isExpectedToFail() -> bool
148
149         Check whether this test is expected to fail in the current
150         configuration. This check relies on the test xfails property which by
151         some test formats may not be computed until the test has first been
152         executed.
153         """
154
155         # Check if any of the xfails match an available feature or the target.
156         for item in self.xfails:
157             # If this is the wildcard, it always fails.
158             if item == '*':
159                 return True
160
161             # If this is an exact match for one of the features, it fails.
162             if item in self.config.available_features:
163                 return True
164
165             # If this is a part of the target triple, it fails.
166             if item in self.suite.config.target_triple:
167                 return True
168
169         return False