Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Side by Side Diff: tools/testrunner/local/old_statusfile.py

Issue 23498058: Migrate to new test status file syntax (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: rebased Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « test/webkit/webkit.status ('k') | tools/testrunner/local/statusfile.py » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2012 the V8 project authors. All rights reserved.
2 # Redistribution and use in source and binary forms, with or without
3 # modification, are permitted provided that the following conditions are
4 # met:
5 #
6 # * Redistributions of source code must retain the above copyright
7 # notice, this list of conditions and the following disclaimer.
8 # * Redistributions in binary form must reproduce the above
9 # copyright notice, this list of conditions and the following
10 # disclaimer in the documentation and/or other materials provided
11 # with the distribution.
12 # * Neither the name of Google Inc. nor the names of its
13 # contributors may be used to endorse or promote products derived
14 # from this software without specific prior written permission.
15 #
16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28
29 import cStringIO
30 import re
31
32 # These outcomes can occur in a TestCase's outcomes list:
33 SKIP = 'SKIP'
34 FAIL = 'FAIL'
35 PASS = 'PASS'
36 OKAY = 'OKAY'
37 TIMEOUT = 'TIMEOUT'
38 CRASH = 'CRASH'
39 SLOW = 'SLOW'
40 FLAKY = 'FLAKY'
41 # These are just for the status files and are mapped below in DEFS:
42 FAIL_OK = 'FAIL_OK'
43 PASS_OR_FAIL = 'PASS_OR_FAIL'
44
45 KEYWORDS = {SKIP: SKIP,
46 FAIL: FAIL,
47 PASS: PASS,
48 OKAY: OKAY,
49 TIMEOUT: TIMEOUT,
50 CRASH: CRASH,
51 SLOW: SLOW,
52 FLAKY: FLAKY,
53 FAIL_OK: FAIL_OK,
54 PASS_OR_FAIL: PASS_OR_FAIL}
55
56 class Expression(object):
57 pass
58
59
60 class Constant(Expression):
61
62 def __init__(self, value):
63 self.value = value
64
65 def Evaluate(self, env, defs):
66 return self.value
67
68
69 class Variable(Expression):
70
71 def __init__(self, name):
72 self.name = name
73
74 def GetOutcomes(self, env, defs):
75 if self.name in env: return set([env[self.name]])
76 else: return set([])
77
78 def Evaluate(self, env, defs):
79 return env[self.name]
80
81 def __str__(self):
82 return self.name
83
84 def string(self, logical):
85 return self.__str__()
86
87
88 class Outcome(Expression):
89
90 def __init__(self, name):
91 self.name = name
92
93 def GetOutcomes(self, env, defs):
94 if self.name in defs:
95 return defs[self.name].GetOutcomes(env, defs)
96 else:
97 return set([self.name])
98
99 def __str__(self):
100 if self.name in KEYWORDS:
101 return "%s" % KEYWORDS[self.name]
102 return "'%s'" % self.name
103
104 def string(self, logical):
105 if logical:
106 return "%s" % self.name
107 return self.__str__()
108
109
110 class Operation(Expression):
111
112 def __init__(self, left, op, right):
113 self.left = left
114 self.op = op
115 self.right = right
116
117 def Evaluate(self, env, defs):
118 if self.op == '||' or self.op == ',':
119 return self.left.Evaluate(env, defs) or self.right.Evaluate(env, defs)
120 elif self.op == 'if':
121 return False
122 elif self.op == '==':
123 return not self.left.GetOutcomes(env, defs).isdisjoint(self.right.GetOutco mes(env, defs))
124 elif self.op == '!=':
125 return self.left.GetOutcomes(env, defs).isdisjoint(self.right.GetOutcomes( env, defs))
126 else:
127 assert self.op == '&&'
128 return self.left.Evaluate(env, defs) and self.right.Evaluate(env, defs)
129
130 def GetOutcomes(self, env, defs):
131 if self.op == '||' or self.op == ',':
132 return self.left.GetOutcomes(env, defs) | self.right.GetOutcomes(env, defs )
133 elif self.op == 'if':
134 if self.right.Evaluate(env, defs): return self.left.GetOutcomes(env, defs)
135 else: return set([])
136 else:
137 assert self.op == '&&'
138 return self.left.GetOutcomes(env, defs) & self.right.GetOutcomes(env, defs )
139
140 def __str__(self):
141 return self.string(False)
142
143 def string(self, logical=False):
144 if self.op == 'if':
145 return "['%s', %s]" % (self.right.string(True), self.left.string(logical))
146 elif self.op == "||" or self.op == ",":
147 if logical:
148 return "%s or %s" % (self.left.string(True), self.right.string(True))
149 else:
150 return "%s, %s" % (self.left, self.right)
151 elif self.op == "&&":
152 return "%s and %s" % (self.left.string(True), self.right.string(True))
153 return "%s %s %s" % (self.left.string(logical), self.op,
154 self.right.string(logical))
155
156
157 def IsAlpha(string):
158 for char in string:
159 if not (char.isalpha() or char.isdigit() or char == '_'):
160 return False
161 return True
162
163
164 class Tokenizer(object):
165 """A simple string tokenizer that chops expressions into variables,
166 parens and operators"""
167
168 def __init__(self, expr):
169 self.index = 0
170 self.expr = expr
171 self.length = len(expr)
172 self.tokens = None
173
174 def Current(self, length=1):
175 if not self.HasMore(length): return ""
176 return self.expr[self.index:self.index + length]
177
178 def HasMore(self, length=1):
179 return self.index < self.length + (length - 1)
180
181 def Advance(self, count=1):
182 self.index = self.index + count
183
184 def AddToken(self, token):
185 self.tokens.append(token)
186
187 def SkipSpaces(self):
188 while self.HasMore() and self.Current().isspace():
189 self.Advance()
190
191 def Tokenize(self):
192 self.tokens = [ ]
193 while self.HasMore():
194 self.SkipSpaces()
195 if not self.HasMore():
196 return None
197 if self.Current() == '(':
198 self.AddToken('(')
199 self.Advance()
200 elif self.Current() == ')':
201 self.AddToken(')')
202 self.Advance()
203 elif self.Current() == '$':
204 self.AddToken('$')
205 self.Advance()
206 elif self.Current() == ',':
207 self.AddToken(',')
208 self.Advance()
209 elif IsAlpha(self.Current()):
210 buf = ""
211 while self.HasMore() and IsAlpha(self.Current()):
212 buf += self.Current()
213 self.Advance()
214 self.AddToken(buf)
215 elif self.Current(2) == '&&':
216 self.AddToken('&&')
217 self.Advance(2)
218 elif self.Current(2) == '||':
219 self.AddToken('||')
220 self.Advance(2)
221 elif self.Current(2) == '==':
222 self.AddToken('==')
223 self.Advance(2)
224 elif self.Current(2) == '!=':
225 self.AddToken('!=')
226 self.Advance(2)
227 else:
228 return None
229 return self.tokens
230
231
232 class Scanner(object):
233 """A simple scanner that can serve out tokens from a given list"""
234
235 def __init__(self, tokens):
236 self.tokens = tokens
237 self.length = len(tokens)
238 self.index = 0
239
240 def HasMore(self):
241 return self.index < self.length
242
243 def Current(self):
244 return self.tokens[self.index]
245
246 def Advance(self):
247 self.index = self.index + 1
248
249
250 def ParseAtomicExpression(scan):
251 if scan.Current() == "true":
252 scan.Advance()
253 return Constant(True)
254 elif scan.Current() == "false":
255 scan.Advance()
256 return Constant(False)
257 elif IsAlpha(scan.Current()):
258 name = scan.Current()
259 scan.Advance()
260 return Outcome(name)
261 elif scan.Current() == '$':
262 scan.Advance()
263 if not IsAlpha(scan.Current()):
264 return None
265 name = scan.Current()
266 scan.Advance()
267 return Variable(name.lower())
268 elif scan.Current() == '(':
269 scan.Advance()
270 result = ParseLogicalExpression(scan)
271 if (not result) or (scan.Current() != ')'):
272 return None
273 scan.Advance()
274 return result
275 else:
276 return None
277
278
279 BINARIES = ['==', '!=']
280 def ParseOperatorExpression(scan):
281 left = ParseAtomicExpression(scan)
282 if not left: return None
283 while scan.HasMore() and (scan.Current() in BINARIES):
284 op = scan.Current()
285 scan.Advance()
286 right = ParseOperatorExpression(scan)
287 if not right:
288 return None
289 left = Operation(left, op, right)
290 return left
291
292
293 def ParseConditionalExpression(scan):
294 left = ParseOperatorExpression(scan)
295 if not left: return None
296 while scan.HasMore() and (scan.Current() == 'if'):
297 scan.Advance()
298 right = ParseOperatorExpression(scan)
299 if not right:
300 return None
301 left = Operation(left, 'if', right)
302 return left
303
304
305 LOGICALS = ["&&", "||", ","]
306 def ParseLogicalExpression(scan):
307 left = ParseConditionalExpression(scan)
308 if not left: return None
309 while scan.HasMore() and (scan.Current() in LOGICALS):
310 op = scan.Current()
311 scan.Advance()
312 right = ParseConditionalExpression(scan)
313 if not right:
314 return None
315 left = Operation(left, op, right)
316 return left
317
318
319 def ParseCondition(expr):
320 """Parses a logical expression into an Expression object"""
321 tokens = Tokenizer(expr).Tokenize()
322 if not tokens:
323 print "Malformed expression: '%s'" % expr
324 return None
325 scan = Scanner(tokens)
326 ast = ParseLogicalExpression(scan)
327 if not ast:
328 print "Malformed expression: '%s'" % expr
329 return None
330 if scan.HasMore():
331 print "Malformed expression: '%s'" % expr
332 return None
333 return ast
334
335
336 class Section(object):
337 """A section of the configuration file. Sections are enabled or
338 disabled prior to running the tests, based on their conditions"""
339
340 def __init__(self, condition):
341 self.condition = condition
342 self.rules = [ ]
343
344 def AddRule(self, rule):
345 self.rules.append(rule)
346
347
348 class Rule(object):
349 """A single rule that specifies the expected outcome for a single
350 test."""
351
352 def __init__(self, raw_path, path, value):
353 self.raw_path = raw_path
354 self.path = path
355 self.value = value
356
357 def GetOutcomes(self, env, defs):
358 return self.value.GetOutcomes(env, defs)
359
360 def Contains(self, path):
361 if len(self.path) > len(path):
362 return False
363 for i in xrange(len(self.path)):
364 if not self.path[i].match(path[i]):
365 return False
366 return True
367
368
369 HEADER_PATTERN = re.compile(r'\[([^]]+)\]')
370 RULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
371 DEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
372 PREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$')
373
374
375 class ConvertNotation(object):
376 def __init__(self, path):
377 self.path = path
378 self.indent = ""
379 self.comment = []
380 self.init = False
381 self.section = False
382 self.out = cStringIO.StringIO()
383
384 def OpenGlobal(self):
385 if self.init: return
386 self.WriteComment()
387 print >> self.out, "["
388 self.init = True
389
390 def CloseGlobal(self):
391 if not self.init: self.OpenGlobal()
392 print >> self.out, "]"
393 self.init = False
394
395 def OpenSection(self, condition="ALWAYS"):
396 if self.section: return
397 self.OpenGlobal()
398 if type(condition) != str:
399 condition = "'%s'" % condition.string(True)
400 print >> self.out, "%s[%s, {" % (self.indent, condition)
401 self.indent += " " * 2
402 self.section = condition
403
404 def CloseSection(self):
405 if not self.section: return
406 self.indent = self.indent[:-2]
407 print >> self.out, "%s}], # %s" % (self.indent, self.section)
408 self.section = False
409
410 def WriteComment(self):
411 if not self.comment: return
412 for c in self.comment:
413 if len(c.strip()) == 0:
414 print >> self.out, ""
415 else:
416 print >> self.out, "%s%s" % (self.indent, c),
417 self.comment = []
418
419 def GetOutput(self):
420 with open(self.path) as f:
421 for line in f:
422 if line[0] == '#':
423 self.comment += [line]
424 continue
425 if len(line.strip()) == 0:
426 self.comment += [line]
427 continue
428 header_match = HEADER_PATTERN.match(line)
429 if header_match:
430 condition = ParseCondition(header_match.group(1).strip())
431 self.CloseSection()
432 self.WriteComment()
433 self.OpenSection(condition)
434 continue
435 rule_match = RULE_PATTERN.match(line)
436 if rule_match:
437 self.OpenSection()
438 self.WriteComment()
439 path = rule_match.group(1).strip()
440 value_str = rule_match.group(2).strip()
441 comment = ""
442 if '#' in value_str:
443 pos = value_str.find('#')
444 comment = " %s" % value_str[pos:].strip()
445 value_str = value_str[:pos].strip()
446 value = ParseCondition(value_str)
447 print >> self.out, ("%s'%s': [%s],%s" %
448 (self.indent, path, value, comment))
449 continue
450 def_match = DEF_PATTERN.match(line)
451 if def_match:
452 # Custom definitions are deprecated.
453 continue
454 prefix_match = PREFIX_PATTERN.match(line)
455 if prefix_match:
456 continue
457 print "Malformed line: '%s'." % line
458 self.CloseSection()
459 self.CloseGlobal()
460 result = self.out.getvalue()
461 self.out.close()
462 return result
OLDNEW
« no previous file with comments | « test/webkit/webkit.status ('k') | tools/testrunner/local/statusfile.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698