blob: dcc49cd62d4a7ebe3105c877893c0dc5e05bbd56 [file] [log] [blame]
mbligh99c2c6f2008-07-11 18:15:46 +00001#
2# Copyright 2008 Google Inc. Released under the GPL v2
3
mbligh4b5c31e2009-07-11 00:55:34 +00004import compiler, textwrap, types
mbligh99c2c6f2008-07-11 18:15:46 +00005
6
7REQUIRED_VARS = set(['author', 'doc', 'name', 'time', 'test_class',
8 'test_category', 'test_type'])
9
10class ControlVariableException(Exception):
11 pass
12
13
14class ControlData(object):
mblighd7cd9832008-10-02 16:20:37 +000015 def __init__(self, vars, path, raise_warnings=False):
mbligh99c2c6f2008-07-11 18:15:46 +000016 # Defaults
mblighd7cd9832008-10-02 16:20:37 +000017 self.path = path
mbligh99c2c6f2008-07-11 18:15:46 +000018 self.dependencies = set()
19 self.experimental = False
20 self.run_verify = True
21 self.sync_count = 1
Eric Li7edb3042011-01-06 17:57:17 -080022 self.test_parameters = set()
mbligh99c2c6f2008-07-11 18:15:46 +000023
24 diff = REQUIRED_VARS - set(vars)
25 if len(diff) > 0:
26 warning = ("WARNING: Not all required control "
mblighd7cd9832008-10-02 16:20:37 +000027 "variables were specified in %s. Please define "
28 "%s.") % (self.path, ', '.join(diff))
mbligh99c2c6f2008-07-11 18:15:46 +000029 if raise_warnings:
30 raise ControlVariableException(warning)
31 print textwrap.wrap(warning, 80)
32
33 for key, val in vars.iteritems():
34 try:
35 self.set_attr(key, val, raise_warnings)
36 except Exception, e:
37 if raise_warnings:
38 raise
39 print "WARNING: %s; skipping" % e
40
41
42 def set_attr(self, attr, val, raise_warnings=False):
43 attr = attr.lower()
44 try:
45 set_fn = getattr(self, 'set_%s' % attr)
46 set_fn(val)
47 except AttributeError:
48 # This must not be a variable we care about
49 pass
50
51
52 def _set_string(self, attr, val):
53 val = str(val)
54 setattr(self, attr, val)
55
56
57 def _set_option(self, attr, val, options):
58 val = str(val)
59 if val.lower() not in [x.lower() for x in options]:
60 raise ValueError("%s must be one of the following "
61 "options: %s" % (attr,
62 ', '.join(options)))
63 setattr(self, attr, val)
64
65
66 def _set_bool(self, attr, val):
67 val = str(val).lower()
68 if val == "false":
69 val = False
70 elif val == "true":
71 val = True
72 else:
73 msg = "%s must be either true or false" % attr
74 raise ValueError(msg)
75 setattr(self, attr, val)
76
77
78 def _set_int(self, attr, val, min=None, max=None):
79 val = int(val)
80 if min is not None and min > val:
81 raise ValueError("%s is %d, which is below the "
82 "minimum of %d" % (attr, val, min))
83 if max is not None and max < val:
84 raise ValueError("%s is %d, which is above the "
85 "maximum of %d" % (attr, val, max))
86 setattr(self, attr, val)
87
88
89 def _set_set(self, attr, val):
90 val = str(val)
91 items = [x.strip() for x in val.split(',')]
92 setattr(self, attr, set(items))
93
94
95 def set_author(self, val):
96 self._set_string('author', val)
97
98
99 def set_dependencies(self, val):
100 self._set_set('dependencies', val)
101
102
103 def set_doc(self, val):
104 self._set_string('doc', val)
105
106
107 def set_experimental(self, val):
108 self._set_bool('experimental', val)
109
110
111 def set_name(self, val):
112 self._set_string('name', val)
113
114
115 def set_run_verify(self, val):
116 self._set_bool('run_verify', val)
117
118
119 def set_sync_count(self, val):
120 self._set_int('sync_count', val, min=1)
121
122
123 def set_time(self, val):
124 self._set_option('time', val, ['short', 'medium', 'long'])
125
126
127 def set_test_class(self, val):
128 self._set_string('test_class', val.lower())
129
130
131 def set_test_category(self, val):
132 self._set_string('test_category', val.lower())
133
134
135 def set_test_type(self, val):
136 self._set_option('test_type', val, ['client', 'server'])
137
Eric Li7edb3042011-01-06 17:57:17 -0800138
Eric Lid3e8a3b2010-12-23 10:02:07 -0800139 def set_test_parameters(self, val):
140 self._set_set('test_parameters', val)
141
mbligh99c2c6f2008-07-11 18:15:46 +0000142
mbligh93f42092008-07-18 01:01:58 +0000143def _extract_const(n):
144 assert(n.__class__ == compiler.ast.Assign)
145 assert(n.expr.__class__ == compiler.ast.Const)
146 assert(n.expr.value.__class__ in (str, int, float, unicode))
147 assert(n.nodes.__class__ == list)
148 assert(len(n.nodes) == 1)
149 assert(n.nodes[0].__class__ == compiler.ast.AssName)
150 assert(n.nodes[0].flags.__class__ == str)
151 assert(n.nodes[0].name.__class__ == str)
152
153 key = n.nodes[0].name.lower()
154 val = str(n.expr.value).strip()
155
156 return (key, val)
157
158
159def _extract_name(n):
160 assert(n.__class__ == compiler.ast.Assign)
161 assert(n.expr.__class__ == compiler.ast.Name)
162 assert(n.nodes.__class__ == list)
163 assert(len(n.nodes) == 1)
164 assert(n.nodes[0].__class__ == compiler.ast.AssName)
165 assert(n.nodes[0].flags.__class__ == str)
166 assert(n.nodes[0].name.__class__ == str)
167 assert(n.expr.name in ('False', 'True', 'None'))
168
169 key = n.nodes[0].name.lower()
170 val = str(n.expr.name)
171
172 return (key, val)
173
174
mbligh99c2c6f2008-07-11 18:15:46 +0000175def parse_control(path, raise_warnings=False):
mblighd7cd9832008-10-02 16:20:37 +0000176 try:
177 mod = compiler.parseFile(path)
178 except SyntaxError, e:
mbligh4b5c31e2009-07-11 00:55:34 +0000179 raise ControlVariableException("Error parsing %s because %s" %
180 (path, e))
mbligh99c2c6f2008-07-11 18:15:46 +0000181
182 assert(mod.__class__ == compiler.ast.Module)
183 assert(mod.node.__class__ == compiler.ast.Stmt)
184 assert(mod.node.nodes.__class__ == list)
185
186 vars = {}
187 for n in mod.node.nodes:
mbligh93f42092008-07-18 01:01:58 +0000188 for fn in (_extract_const, _extract_name):
189 try:
mbligh93f42092008-07-18 01:01:58 +0000190 key, val = fn(n)
mbligh99c2c6f2008-07-11 18:15:46 +0000191
mbligh93f42092008-07-18 01:01:58 +0000192 vars[key] = val
193 except AssertionError, e:
194 pass
mbligh99c2c6f2008-07-11 18:15:46 +0000195
mblighd7cd9832008-10-02 16:20:37 +0000196 return ControlData(vars, path, raise_warnings)