1a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#!/usr/bin/env python
2a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#
33ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch# Copyright 2012 the V8 project authors. All rights reserved.
4a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# Redistribution and use in source and binary forms, with or without
5a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# modification, are permitted provided that the following conditions are
6a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# met:
7a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#
8a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#     * Redistributions of source code must retain the above copyright
9a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       notice, this list of conditions and the following disclaimer.
10a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#     * Redistributions in binary form must reproduce the above
11a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       copyright notice, this list of conditions and the following
12a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       disclaimer in the documentation and/or other materials provided
13a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       with the distribution.
14a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#     * Neither the name of Google Inc. nor the names of its
15a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       contributors may be used to endorse or promote products derived
16a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#       from this software without specific prior written permission.
17a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block#
18a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
30a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
31a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport imp
32a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport optparse
33a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport os
34a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfrom os.path import join, dirname, abspath, basename, isdir, exists
35a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport platform
36a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport re
37a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport signal
38a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport subprocess
39a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport sys
40a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport tempfile
41a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport time
42a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport threading
43a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockimport utils
44a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockfrom Queue import Queue, Empty
45a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
46a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
47a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockVERBOSE = False
48a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
49a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
50a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# ---------------------------------------------
51a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# --- P r o g r e s s   I n d i c a t o r s ---
52a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# ---------------------------------------------
53a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
54a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
55a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ProgressIndicator(object):
56a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
57a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, cases):
58a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.cases = cases
59a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.queue = Queue(len(cases))
60a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for case in cases:
61a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.queue.put_nowait(case)
62a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.succeeded = 0
63a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.remaining = len(cases)
64a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.total = len(cases)
65a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.failed = [ ]
66a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.crashed = 0
67a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.terminate = False
68a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.lock = threading.Lock()
69a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
70a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def PrintFailureHeader(self, test):
71a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if test.IsNegative():
72a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      negative_marker = '[negative] '
73a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
74a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      negative_marker = ''
75a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "=== %(label)s %(negative)s===" % {
76a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'label': test.GetLabel(),
77a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'negative': negative_marker
78a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
79a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "Path: %s" % "/".join(test.path)
80a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
81a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Run(self, tasks):
82a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.Starting()
83a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    threads = []
84a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # Spawn N-1 threads and then use this thread as the last one.
85a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # That way -j1 avoids threading altogether which is a nice fallback
86a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # in case of threading problems.
87a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for i in xrange(tasks - 1):
88a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      thread = threading.Thread(target=self.RunSingle, args=[])
89a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      threads.append(thread)
90a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      thread.start()
91a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    try:
92a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.RunSingle()
93a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # Wait for the remaining threads
94a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      for thread in threads:
95a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        # Use a timeout so that signals (ctrl-c) will be processed.
96a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        thread.join(timeout=10000000)
97a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    except Exception, e:
98a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # If there's an exception we schedule an interruption for any
99a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # remaining threads.
100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.terminate = True
101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # ...and then reraise the exception to bail out
102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      raise
103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.Done()
104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return not self.failed
105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def RunSingle(self):
107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while not self.terminate:
108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      try:
109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        test = self.queue.get_nowait()
110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      except Empty:
111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return
112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case = test.case
113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.lock.acquire()
114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.AboutToRun(case)
115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.lock.release()
116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      try:
117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        start = time.time()
118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        output = case.Run()
119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        case.duration = (time.time() - start)
120257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      except BreakNowException:
121257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch        self.terminate = True
122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      except IOError, e:
123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        assert self.terminate
124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return
125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if self.terminate:
126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return
127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.lock.acquire()
128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if output.UnexpectedOutput():
129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.failed.append(output)
130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        if output.HasCrashed():
131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          self.crashed += 1
132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.succeeded += 1
134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.remaining -= 1
135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.HasRun(output)
136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.lock.release()
137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef EscapeCommand(command):
140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  parts = []
141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for part in command:
142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if ' ' in part:
143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # Escape spaces.  We may need to escape more characters for this
144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # to work properly.
145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      parts.append('"%s"' % part)
146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      parts.append(part)
148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return " ".join(parts)
149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass SimpleProgressIndicator(ProgressIndicator):
152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Starting(self):
154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print 'Running %i tests' % len(self.cases)
155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Done(self):
157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print
158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for failed in self.failed:
159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.PrintFailureHeader(failed.test)
160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if failed.output.stderr:
161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- stderr ---"
162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print failed.output.stderr.strip()
163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if failed.output.stdout:
164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- stdout ---"
165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print failed.output.stdout.strip()
166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "Command: %s" % EscapeCommand(failed.command)
167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if failed.HasCrashed():
168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- CRASHED ---"
169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if failed.HasTimedOut():
170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- TIMEOUT ---"
171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if len(self.failed) == 0:
172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "==="
173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "=== All tests succeeded"
174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "==="
175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print
177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "==="
178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "=== %i tests failed" % len(self.failed)
179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if self.crashed > 0:
180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "=== %i tests CRASHED" % self.crashed
181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "==="
182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass VerboseProgressIndicator(SimpleProgressIndicator):
185a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def AboutToRun(self, case):
187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print 'Starting %s...' % case.GetLabel()
188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sys.stdout.flush()
189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasRun(self, output):
191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if output.UnexpectedOutput():
192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if output.HasCrashed():
193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        outcome = 'CRASH'
194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        outcome = 'FAIL'
196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcome = 'pass'
198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print 'Done running %s: %s' % (output.test.GetLabel(), outcome)
199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass DotsProgressIndicator(SimpleProgressIndicator):
202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
203a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def AboutToRun(self, case):
204a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pass
205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasRun(self, output):
207a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    total = self.succeeded + len(self.failed)
208a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (total > 1) and (total % 50 == 1):
209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sys.stdout.write('\n')
210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if output.UnexpectedOutput():
211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if output.HasCrashed():
212a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.write('C')
213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.flush()
214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif output.HasTimedOut():
215a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.write('T')
216a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.flush()
217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.write('F')
219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sys.stdout.flush()
220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sys.stdout.write('.')
222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sys.stdout.flush()
223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CompactProgressIndicator(ProgressIndicator):
226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, cases, templates):
228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    super(CompactProgressIndicator, self).__init__(cases)
229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.templates = templates
230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.last_status_length = 0
231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.start_time = time.time()
232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Starting(self):
234a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pass
235a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
236a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Done(self):
237a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.PrintProgress('Done')
238a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
239a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def AboutToRun(self, case):
240a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.PrintProgress(case.GetLabel())
241a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
242a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasRun(self, output):
243a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if output.UnexpectedOutput():
244a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.ClearLine(self.last_status_length)
245a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.PrintFailureHeader(output.test)
246a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      stdout = output.output.stdout.strip()
247a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if len(stdout):
248a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print self.templates['stdout'] % stdout
249a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      stderr = output.output.stderr.strip()
250a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if len(stderr):
251a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print self.templates['stderr'] % stderr
252a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "Command: %s" % EscapeCommand(output.command)
253a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if output.HasCrashed():
254a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- CRASHED ---"
255a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if output.HasTimedOut():
256a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "--- TIMEOUT ---"
257a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
258a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Truncate(self, str, length):
259a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if length and (len(str) > (length - 3)):
260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return str[:(length-3)] + "..."
261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return str
263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def PrintProgress(self, name):
265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.ClearLine(self.last_status_length)
266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elapsed = time.time() - self.start_time
267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    status = self.templates['status_line'] % {
268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'passed': self.succeeded,
269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'remaining': (((self.total - self.remaining) * 100) // self.total),
270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'failed': len(self.failed),
271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'test': name,
272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'mins': int(elapsed) / 60,
273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'secs': int(elapsed) % 60
274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    status = self.Truncate(status, 78)
276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.last_status_length = len(status)
277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print status,
278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sys.stdout.flush()
279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ColorProgressIndicator(CompactProgressIndicator):
282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, cases):
284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    templates = {
285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'status_line': "[%(mins)02i:%(secs)02i|\033[34m%%%(remaining) 4d\033[0m|\033[32m+%(passed) 4d\033[0m|\033[31m-%(failed) 4d\033[0m]: %(test)s",
286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'stdout': "\033[1m%s\033[0m",
287a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'stderr': "\033[31m%s\033[0m",
288a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
289a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    super(ColorProgressIndicator, self).__init__(cases, templates)
290a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
291a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def ClearLine(self, last_line_length):
292a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "\033[1K\r",
293a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
294a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
295a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass MonochromeProgressIndicator(CompactProgressIndicator):
296a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
297a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, cases):
298a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    templates = {
299a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'status_line': "[%(mins)02i:%(secs)02i|%%%(remaining) 4d|+%(passed) 4d|-%(failed) 4d]: %(test)s",
300a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'stdout': '%s',
301a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'stderr': '%s',
302a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'clear': lambda last_line_length: ("\r" + (" " * last_line_length) + "\r"),
303a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      'max_length': 78
304a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    }
305a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    super(MonochromeProgressIndicator, self).__init__(cases, templates)
306a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
307a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def ClearLine(self, last_line_length):
308a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print ("\r" + (" " * last_line_length) + "\r"),
309a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
310a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
311a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPROGRESS_INDICATORS = {
312a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  'verbose': VerboseProgressIndicator,
313a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  'dots': DotsProgressIndicator,
314a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  'color': ColorProgressIndicator,
315a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  'mono': MonochromeProgressIndicator
316a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block}
317a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
318a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
319a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# -------------------------
320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# --- F r a m e w o r k ---
321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# -------------------------
322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
323257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdochclass BreakNowException(Exception):
324257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __init__(self, value):
325257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    self.value = value
326257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def __str__(self):
327257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return repr(self.value)
328257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
330a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass CommandOutput(object):
331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, exit_code, timed_out, stdout, stderr):
333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.exit_code = exit_code
334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.timed_out = timed_out
335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.stdout = stdout
336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.stderr = stderr
3373ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    self.failed = None
338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TestCase(object):
341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
34280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def __init__(self, context, path, mode):
343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.path = path
344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.context = context
345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.duration = None
34680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    self.mode = mode
347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsNegative(self):
349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return False
350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
35144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  def TestsIsolates(self):
35244f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return False
35344f0eee88ff00398ff7f715fab053374d808c90dSteve Block
354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def CompareTime(self, other):
355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return cmp(other.duration, self.duration)
356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def DidFail(self, output):
3583ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    if output.failed is None:
3593ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block      output.failed = self.IsFailureOutput(output)
3603ce2e2076e8e3e60cf1810eec160ea2d8557e9e7Steve Block    return output.failed
361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsFailureOutput(self, output):
363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return output.exit_code != 0
364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetSource(self):
366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return "(no source available)"
367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def RunCommand(self, command):
369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    full_command = self.context.processor(command)
37080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    output = Execute(full_command,
37180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                     self.context,
372b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                     self.context.GetTimeout(self, self.mode))
373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.Cleanup()
37480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return TestOutput(self,
37580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      full_command,
37680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      output,
37780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                      self.context.store_unexpected_output)
378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
379d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  def BeforeRun(self):
380d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    pass
381d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
38280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def AfterRun(self, result):
383d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    pass
384d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block
38544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  def GetCustomFlags(self, mode):
38644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return None
38744f0eee88ff00398ff7f715fab053374d808c90dSteve Block
388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Run(self):
389d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    self.BeforeRun()
390257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    result = None
391d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    try:
392d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      result = self.RunCommand(self.GetCommand())
393257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    except:
394257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      self.terminate = True
395257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      raise BreakNowException("User pressed CTRL+C or IO went wrong")
396d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    finally:
39780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      self.AfterRun(result)
398d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    return result
399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Cleanup(self):
401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return
402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
403a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
404a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TestOutput(object):
405a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
40680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def __init__(self, test, command, output, store_unexpected_output):
407a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.test = test
408a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.command = command
409a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.output = output
41080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    self.store_unexpected_output = store_unexpected_output
411a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
412a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def UnexpectedOutput(self):
413a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.HasCrashed():
414a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcome = CRASH
415a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elif self.HasTimedOut():
416a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcome = TIMEOUT
417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elif self.HasFailed():
418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcome = FAIL
419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcome = PASS
421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return not outcome in self.test.outcomes
422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
42380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def HasPreciousOutput(self):
42480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return self.UnexpectedOutput() and self.store_unexpected_output
42580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasCrashed(self):
427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if utils.IsWindows():
428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return 0x80000000 & self.output.exit_code and not (0x3FFFFF00 & self.output.exit_code)
429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # Timed out tests will have exit_code -signal.SIGTERM.
431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if self.output.timed_out:
432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.output.exit_code < 0 and \
434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block             self.output.exit_code != -signal.SIGABRT
435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasTimedOut(self):
437257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return self.output.timed_out
438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasFailed(self):
440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    execution_failed = self.test.DidFail(self.output)
441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.test.IsNegative():
442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return not execution_failed
443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return execution_failed
445a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
446a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
447a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef KillProcessWithID(pid):
448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if utils.IsWindows():
449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    os.popen('taskkill /T /F /PID %d' % pid)
450a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    os.kill(pid, signal.SIGTERM)
452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockMAX_SLEEP_TIME = 0.1
455a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockINITIAL_SLEEP_TIME = 0.0001
456a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSLEEP_TIME_FACTOR = 1.25
457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSEM_INVALID_VALUE = -1
459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSEM_NOGPFAULTERRORBOX = 0x0002 # Microsoft Platform SDK WinBase.h
460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef Win32SetErrorMode(mode):
462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  prev_error_mode = SEM_INVALID_VALUE
463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  try:
464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    import ctypes
465257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    prev_error_mode = ctypes.windll.kernel32.SetErrorMode(mode)
466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  except ImportError:
467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pass
468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return prev_error_mode
469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef RunProcess(context, timeout, args, **rest):
471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if context.verbose: print "#", " ".join(args)
472a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  popen_args = args
473257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  prev_error_mode = SEM_INVALID_VALUE
474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if utils.IsWindows():
4753ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    popen_args = subprocess.list2cmdline(args)
476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if context.suppress_dialogs:
477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # Try to change the error mode to avoid dialogs on fatal errors. Don't
478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # touch any existing error mode flags by merging the existing error mode.
479a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # See http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx.
480257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      error_mode = SEM_NOGPFAULTERRORBOX
481257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      prev_error_mode = Win32SetErrorMode(error_mode)
482257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      Win32SetErrorMode(error_mode | prev_error_mode)
483a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  process = subprocess.Popen(
484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    shell = utils.IsWindows(),
485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    args = popen_args,
486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    **rest
487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  )
488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if utils.IsWindows() and context.suppress_dialogs and prev_error_mode != SEM_INVALID_VALUE:
489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    Win32SetErrorMode(prev_error_mode)
490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # Compute the end time - if the process crosses this limit we
491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # consider it timed out.
492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if timeout is None: end_time = None
493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else: end_time = time.time() + timeout
494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  timed_out = False
495a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # Repeatedly check the exit code from the process in a
496a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # loop and keep track of whether or not it times out.
497a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  exit_code = None
498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sleep_time = INITIAL_SLEEP_TIME
499a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while exit_code is None:
500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (not end_time is None) and (time.time() >= end_time):
501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      # Kill the process and wait for it to exit.
502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      KillProcessWithID(process.pid)
503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit_code = process.wait()
504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      timed_out = True
505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
506a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      exit_code = process.poll()
507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      time.sleep(sleep_time)
508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sleep_time = sleep_time * SLEEP_TIME_FACTOR
509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if sleep_time > MAX_SLEEP_TIME:
510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        sleep_time = MAX_SLEEP_TIME
511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return (process, exit_code, timed_out)
512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef PrintError(str):
515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sys.stderr.write(str)
516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sys.stderr.write('\n')
517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef CheckedUnlink(name):
52044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  # On Windows, when run with -jN in parallel processes,
52144f0eee88ff00398ff7f715fab053374d808c90dSteve Block  # OS often fails to unlink the temp file. Not sure why.
52244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  # Need to retry.
52344f0eee88ff00398ff7f715fab053374d808c90dSteve Block  # Idea from https://bugs.webkit.org/attachment.cgi?id=75982&action=prettypatch
52444f0eee88ff00398ff7f715fab053374d808c90dSteve Block  retry_count = 0
52544f0eee88ff00398ff7f715fab053374d808c90dSteve Block  while retry_count < 30:
52644f0eee88ff00398ff7f715fab053374d808c90dSteve Block    try:
52744f0eee88ff00398ff7f715fab053374d808c90dSteve Block      os.unlink(name)
52844f0eee88ff00398ff7f715fab053374d808c90dSteve Block      return
52944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    except OSError, e:
530257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      retry_count += 1
53144f0eee88ff00398ff7f715fab053374d808c90dSteve Block      time.sleep(retry_count * 0.1)
53244f0eee88ff00398ff7f715fab053374d808c90dSteve Block  PrintError("os.unlink() " + str(e))
533a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
534a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef Execute(args, context, timeout=None):
535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  (fd_out, outname) = tempfile.mkstemp()
536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  (fd_err, errname) = tempfile.mkstemp()
537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  (process, exit_code, timed_out) = RunProcess(
538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    context,
539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    timeout,
540a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    args = args,
541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stdout = fd_out,
542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    stderr = fd_err,
543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  )
544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  os.close(fd_out)
545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  os.close(fd_err)
546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  output = file(outname).read()
547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  errors = file(errname).read()
548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CheckedUnlink(outname)
549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  CheckedUnlink(errname)
550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return CommandOutput(exit_code, timed_out, output, errors)
551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ExecuteNoCapture(args, context, timeout=None):
554a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  (process, exit_code, timed_out) = RunProcess(
555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    context,
556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    timeout,
557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    args = args,
558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  )
559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return CommandOutput(exit_code, False, "", "")
560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef CarCdr(path):
563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if len(path) == 0:
564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return (None, [ ])
565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return (path[0], path[1:])
567a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
568a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
569257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch# Use this to run several variants of the tests, e.g.:
570257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch# VARIANT_FLAGS = [[], ['--always_compact', '--noflush_code']]
571257744e915dfc84d6d07a6b2accf8402d9ffc708Ben MurdochVARIANT_FLAGS = [[],
572257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 ['--stress-opt', '--always-opt'],
573257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch                 ['--nocrankshaft']]
574257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
575257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
576a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TestConfiguration(object):
577a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
578a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, context, root):
579a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.context = context
580a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.root = root
581a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
582a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Contains(self, path, file):
583a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if len(path) > len(file):
584a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return False
585a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for i in xrange(len(path)):
586a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not path[i].match(file[i]):
587a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
588a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return True
589a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
590a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetTestStatus(self, sections, defs):
591a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pass
592a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
593257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  def VariantFlags(self):
594257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    return VARIANT_FLAGS
595257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
596257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
597257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch
598a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
599a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TestSuite(object):
600a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
601a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, name):
602a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.name = name
603a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
604a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetName(self):
605a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.name
606a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
607a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
608a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass TestRepository(TestSuite):
609a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
610a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, path):
611a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    normalized_path = abspath(path)
612a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    super(TestRepository, self).__init__(basename(normalized_path))
613a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.path = normalized_path
614a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.is_loaded = False
615a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.config = None
616a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
617a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetConfiguration(self, context):
618a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.is_loaded:
619a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.config
620a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.is_loaded = True
621a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    file = None
622a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    try:
623a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (file, pathname, description) = imp.find_module('testcfg', [ self.path ])
624a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      module = imp.load_module('testcfg', file, pathname, description)
625a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.config = module.GetConfiguration(context, self.path)
626a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    finally:
627a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if file:
628a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        file.close()
629a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.config
630a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
631a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetBuildRequirements(self, path, context):
632a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.GetConfiguration(context).GetBuildRequirements()
633a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  def DownloadData(self, context):
6353ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    config = self.GetConfiguration(context)
6363ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    if 'DownloadData' in dir(config):
6373ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      config.DownloadData()
6383ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
63980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def AddTestsToList(self, result, current_path, path, context, mode):
6403ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    config = self.GetConfiguration(context)
6413ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for v in config.VariantFlags():
6423ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      tests = config.ListTests(current_path, path, mode, v)
64380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      for t in tests: t.variant_flags = v
64480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      result += tests
64580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
646a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetTestStatus(self, context, sections, defs):
647a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.GetConfiguration(context).GetTestStatus(sections, defs)
648a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
649a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
650a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass LiteralTestSuite(TestSuite):
651a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
652a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, tests):
653a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    super(LiteralTestSuite, self).__init__('root')
654a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.tests = tests
655a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
656a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetBuildRequirements(self, path, context):
657a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    (name, rest) = CarCdr(path)
658a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = [ ]
659a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for test in self.tests:
660a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not name or name.match(test.GetName()):
661a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        result += test.GetBuildRequirements(rest, context)
662a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result
663a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
6643ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  def DownloadData(self, path, context):
6653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    (name, rest) = CarCdr(path)
6663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for test in self.tests:
6673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      if not name or name.match(test.GetName()):
6683ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        test.DownloadData(context)
6693ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
67044f0eee88ff00398ff7f715fab053374d808c90dSteve Block  def ListTests(self, current_path, path, context, mode, variant_flags):
671a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    (name, rest) = CarCdr(path)
672a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = [ ]
673a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for test in self.tests:
674a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test_name = test.GetName()
675a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not name or name.match(test_name):
676a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        full_path = current_path + [test_name]
67780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen        test.AddTestsToList(result, full_path, path, context, mode)
678a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result
679a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
680a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetTestStatus(self, context, sections, defs):
681a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for test in self.tests:
682a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      test.GetTestStatus(context, sections, defs)
683a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
684a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
68580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenSUFFIX = {
68680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    'debug'   : '_g',
68780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    'release' : '' }
68880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenFLAGS = {
6893ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    'debug'   : ['--nobreak-on-abort', '--enable-slow-asserts', '--debug-code', '--verify-heap'],
6903ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    'release' : ['--nobreak-on-abort']}
69180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian MonsenTIMEOUT_SCALEFACTOR = {
69280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    'debug'   : 4,
69380d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    'release' : 1 }
694a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
695a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
696a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Context(object):
697a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
69880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def __init__(self, workspace, buildspace, verbose, vm, timeout, processor, suppress_dialogs, store_unexpected_output):
699a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.workspace = workspace
700a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.buildspace = buildspace
701a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.verbose = verbose
702a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.vm_root = vm
703a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.timeout = timeout
704a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.processor = processor
705a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.suppress_dialogs = suppress_dialogs
70680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    self.store_unexpected_output = store_unexpected_output
707a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
708a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetVm(self, mode):
709a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    name = self.vm_root + SUFFIX[mode]
710a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if utils.IsWindows() and not name.endswith('.exe'):
711a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      name = name + '.exe'
712a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return name
713a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
71480d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def GetVmCommand(self, testcase, mode):
71580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen    return [self.GetVm(mode)] + self.GetVmFlags(testcase, mode)
71680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
71780d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen  def GetVmFlags(self, testcase, mode):
71844f0eee88ff00398ff7f715fab053374d808c90dSteve Block    flags = testcase.GetCustomFlags(mode)
71944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    if flags is None:
72044f0eee88ff00398ff7f715fab053374d808c90dSteve Block      flags = FLAGS[mode]
72144f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return testcase.variant_flags + flags
72280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
723b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  def GetTimeout(self, testcase, mode):
724b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    result = self.timeout * TIMEOUT_SCALEFACTOR[mode]
725b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    if '--stress-opt' in self.GetVmFlags(testcase, mode):
7263ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return result * 4
727b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    else:
728b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      return result
72980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
730e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarkedef RunTestCases(cases_to_run, progress, tasks):
731a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  progress = PROGRESS_INDICATORS[progress](cases_to_run)
732257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  result = 0
733257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  try:
734257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    result = progress.Run(tasks)
735257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  except Exception, e:
736257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch    print "\n", e
737257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  return result
738a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
739a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
740a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef BuildRequirements(context, requirements, mode, scons_flags):
741a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  command_line = (['scons', '-Y', context.workspace, 'mode=' + ",".join(mode)]
742a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  + requirements
743a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                  + scons_flags)
744a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  output = ExecuteNoCapture(command_line, context)
745a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return output.exit_code == 0
746a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
747a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
748a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# -------------------------------------------
749a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# --- T e s t   C o n f i g u r a t i o n ---
750a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# -------------------------------------------
751a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
752a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
753a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSKIP = 'skip'
754a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockFAIL = 'fail'
755a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPASS = 'pass'
756a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockOKAY = 'okay'
757a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTIMEOUT = 'timeout'
758a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockCRASH = 'crash'
759a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockSLOW = 'slow'
760a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
761a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
762a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Expression(object):
763a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pass
764a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
765a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
766a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Constant(Expression):
767a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
768a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, value):
769a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.value = value
770a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
771a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Evaluate(self, env, defs):
772a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.value
773a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
774a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
775a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Variable(Expression):
776a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
777a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, name):
778a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.name = name
779a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
780a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetOutcomes(self, env, defs):
781a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.name in env: return ListSet([env[self.name]])
782a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else: return Nothing()
783a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
784b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  def Evaluate(self, env, defs):
785b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    return env[self.name]
786b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch
787a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
788a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Outcome(Expression):
789a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
790a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, name):
791a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.name = name
792a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
793a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetOutcomes(self, env, defs):
794a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.name in defs:
795a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return defs[self.name].GetOutcomes(env, defs)
796a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
797a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return ListSet([self.name])
798a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
799a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
800a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Set(object):
801a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  pass
802a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
803a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
804a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ListSet(Set):
805a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
806a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, elms):
807a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.elms = elms
808a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
809a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __str__(self):
810a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return "ListSet%s" % str(self.elms)
811a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
812a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Intersect(self, that):
813a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not isinstance(that, ListSet):
814a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return that.Intersect(self)
815a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return ListSet([ x for x in self.elms if x in that.elms ])
816a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
817a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Union(self, that):
818a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not isinstance(that, ListSet):
819a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return that.Union(self)
820a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return ListSet(self.elms + [ x for x in that.elms if x not in self.elms ])
821a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
822a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsEmpty(self):
823a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return len(self.elms) == 0
824a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
825a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
826a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Everything(Set):
827a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
828a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Intersect(self, that):
829a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return that
830a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
831a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Union(self, that):
832a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self
833a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
834a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsEmpty(self):
835a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return False
836a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
837a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
838a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Nothing(Set):
839a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
840a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Intersect(self, that):
841a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self
842a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
843a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Union(self, that):
844a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return that
845a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
846a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsEmpty(self):
847a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return True
848a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
849a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
850a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Operation(Expression):
851a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
852a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, left, op, right):
853a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.left = left
854a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.op = op
855a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.right = right
856a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
857a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Evaluate(self, env, defs):
858a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.op == '||' or self.op == ',':
859a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.left.Evaluate(env, defs) or self.right.Evaluate(env, defs)
860a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elif self.op == 'if':
861a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return False
862a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elif self.op == '==':
863a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      inter = self.left.GetOutcomes(env, defs).Intersect(self.right.GetOutcomes(env, defs))
864a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return not inter.IsEmpty()
8653ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    elif self.op == '!=':
8663ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      inter = self.left.GetOutcomes(env, defs).Intersect(self.right.GetOutcomes(env, defs))
8673ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      return inter.IsEmpty()
868a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
869a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      assert self.op == '&&'
870a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.left.Evaluate(env, defs) and self.right.Evaluate(env, defs)
871a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
872a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetOutcomes(self, env, defs):
873a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if self.op == '||' or self.op == ',':
874a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.left.GetOutcomes(env, defs).Union(self.right.GetOutcomes(env, defs))
875a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    elif self.op == 'if':
876a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if self.right.Evaluate(env, defs): return self.left.GetOutcomes(env, defs)
877a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else: return Nothing()
878a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    else:
879a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      assert self.op == '&&'
880a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return self.left.GetOutcomes(env, defs).Intersect(self.right.GetOutcomes(env, defs))
881a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
882a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
883a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef IsAlpha(str):
884a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for char in str:
885a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not (char.isalpha() or char.isdigit() or char == '_'):
886a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return False
887a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return True
888a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
889a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
890a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Tokenizer(object):
891a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """A simple string tokenizer that chops expressions into variables,
892a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  parens and operators"""
893a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
894a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, expr):
895a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.index = 0
896a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.expr = expr
897a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.length = len(expr)
898a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.tokens = None
899a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
900a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Current(self, length = 1):
901a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not self.HasMore(length): return ""
902a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.expr[self.index:self.index+length]
903a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
904a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasMore(self, length = 1):
905a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.index < self.length + (length - 1)
906a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
907a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Advance(self, count = 1):
908a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.index = self.index + count
909a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
910a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def AddToken(self, token):
911a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.tokens.append(token)
912a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
913a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def SkipSpaces(self):
914a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while self.HasMore() and self.Current().isspace():
915a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.Advance()
916a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
917a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Tokenize(self):
918a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.tokens = [ ]
919a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    while self.HasMore():
920a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.SkipSpaces()
921a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not self.HasMore():
922a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return None
923a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if self.Current() == '(':
924a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken('(')
925a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance()
926a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current() == ')':
927a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken(')')
928a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance()
929a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current() == '$':
930a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken('$')
931a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance()
932a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current() == ',':
933a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken(',')
934a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance()
935a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif IsAlpha(self.Current()):
936a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        buf = ""
937a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        while self.HasMore() and IsAlpha(self.Current()):
938a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          buf += self.Current()
939a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block          self.Advance()
940a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken(buf)
941a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current(2) == '&&':
942a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken('&&')
943a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance(2)
944a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current(2) == '||':
945a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken('||')
946a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance(2)
947a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      elif self.Current(2) == '==':
948a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.AddToken('==')
949a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        self.Advance(2)
9503ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      elif self.Current(2) == '!=':
9513ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        self.AddToken('!=')
9523ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch        self.Advance(2)
953a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
954a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return None
955a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.tokens
956a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
957a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
958a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Scanner(object):
959a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """A simple scanner that can serve out tokens from a given list"""
960a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
961a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, tokens):
962a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.tokens = tokens
963a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.length = len(tokens)
964a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.index = 0
965a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
966a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def HasMore(self):
967a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.index < self.length
968a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
969a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Current(self):
970a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.tokens[self.index]
971a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
972a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Advance(self):
973a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.index = self.index + 1
974a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
975a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
976a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ParseAtomicExpression(scan):
977a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if scan.Current() == "true":
978a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
979a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return Constant(True)
980a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  elif scan.Current() == "false":
981a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
982a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return Constant(False)
983a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  elif IsAlpha(scan.Current()):
984a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    name = scan.Current()
985a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
986a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return Outcome(name.lower())
987a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  elif scan.Current() == '$':
988a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
989a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not IsAlpha(scan.Current()):
990a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return None
991a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    name = scan.Current()
992a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
993a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return Variable(name.lower())
994a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  elif scan.Current() == '(':
995a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
996a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = ParseLogicalExpression(scan)
997a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if (not result) or (scan.Current() != ')'):
998a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return None
999a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
1000a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return result
1001a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
1002a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return None
1003a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1004a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
10053ef787dbeca8a5fb1086949cda830dccee07bfbdBen MurdochBINARIES = ['==', '!=']
1006a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ParseOperatorExpression(scan):
1007a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left = ParseAtomicExpression(scan)
1008a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not left: return None
1009a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while scan.HasMore() and (scan.Current() in BINARIES):
1010a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    op = scan.Current()
1011a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
1012a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right = ParseOperatorExpression(scan)
1013a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not right:
1014a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return None
1015a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left = Operation(left, op, right)
1016a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return left
1017a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1018a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1019a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ParseConditionalExpression(scan):
1020a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left = ParseOperatorExpression(scan)
1021a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not left: return None
1022a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while scan.HasMore() and (scan.Current() == 'if'):
1023a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
1024a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right = ParseOperatorExpression(scan)
1025a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not right:
1026a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return None
10273ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    left = Operation(left, 'if', right)
1028a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return left
1029a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1030a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1031a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockLOGICALS = ["&&", "||", ","]
1032a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ParseLogicalExpression(scan):
1033a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  left = ParseConditionalExpression(scan)
1034a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not left: return None
1035a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  while scan.HasMore() and (scan.Current() in LOGICALS):
1036a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    op = scan.Current()
1037a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    scan.Advance()
1038a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    right = ParseConditionalExpression(scan)
1039a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not right:
1040a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return None
1041a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    left = Operation(left, op, right)
1042a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return left
1043a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1044a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1045a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ParseCondition(expr):
1046a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """Parses a logical expression into an Expression object"""
1047a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  tokens = Tokenizer(expr).Tokenize()
1048a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not tokens:
1049a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "Malformed expression: '%s'" % expr
1050a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return None
1051a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  scan = Scanner(tokens)
1052a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  ast = ParseLogicalExpression(scan)
1053a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not ast:
1054a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "Malformed expression: '%s'" % expr
1055a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return None
1056a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if scan.HasMore():
1057a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "Malformed expression: '%s'" % expr
1058a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return None
1059a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return ast
1060a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1061a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1062a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass ClassifiedTest(object):
1063a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1064a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, case, outcomes):
1065a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.case = case
1066a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.outcomes = outcomes
1067a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
106844f0eee88ff00398ff7f715fab053374d808c90dSteve Block  def TestsIsolates(self):
106944f0eee88ff00398ff7f715fab053374d808c90dSteve Block    return self.case.TestsIsolates()
107044f0eee88ff00398ff7f715fab053374d808c90dSteve Block
1071a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1072a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Configuration(object):
1073a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """The parsed contents of a configuration file"""
1074a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1075a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, sections, defs):
1076a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.sections = sections
1077a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.defs = defs
1078a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1079a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def ClassifyTests(self, cases, env):
1080a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sections = [s for s in self.sections if s.condition.Evaluate(env, self.defs)]
1081a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    all_rules = reduce(list.__add__, [s.rules for s in sections], [])
1082a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    unused_rules = set(all_rules)
1083a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    result = [ ]
1084a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    all_outcomes = set([])
1085a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for case in cases:
1086a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      matches = [ r for r in all_rules if r.Contains(case.path) ]
1087a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      outcomes = set([])
1088a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      for rule in matches:
1089a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        outcomes = outcomes.union(rule.GetOutcomes(env, self.defs))
1090a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        unused_rules.discard(rule)
1091a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not outcomes:
1092a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        outcomes = [PASS]
1093a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      case.outcomes = outcomes
1094a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      all_outcomes = all_outcomes.union(outcomes)
1095a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      result.append(ClassifiedTest(case, outcomes))
1096a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return (result, list(unused_rules), all_outcomes)
1097a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1098a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1099a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Section(object):
1100a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """A section of the configuration file.  Sections are enabled or
1101a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  disabled prior to running the tests, based on their conditions"""
1102a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1103a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, condition):
1104a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.condition = condition
1105a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.rules = [ ]
1106a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1107a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def AddRule(self, rule):
1108a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.rules.append(rule)
1109a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1110a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1111a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Rule(object):
1112a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  """A single rule that specifies the expected outcome for a single
1113a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  test."""
1114a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1115a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, raw_path, path, value):
1116a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.raw_path = raw_path
1117a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.path = path
1118a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.value = value
1119a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1120a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def GetOutcomes(self, env, defs):
1121a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    set = self.value.GetOutcomes(env, defs)
1122a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    assert isinstance(set, ListSet)
1123a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return set.elms
1124a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1125a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def Contains(self, path):
1126a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if len(self.path) > len(path):
1127a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return False
1128a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for i in xrange(len(self.path)):
1129a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not self.path[i].match(path[i]):
1130a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
1131a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return True
1132a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1133a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1134a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockHEADER_PATTERN = re.compile(r'\[([^]]+)\]')
1135a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockRULE_PATTERN = re.compile(r'\s*([^: ]*)\s*:(.*)')
1136a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockDEF_PATTERN = re.compile(r'^def\s*(\w+)\s*=(.*)$')
1137a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockPREFIX_PATTERN = re.compile(r'^\s*prefix\s+([\w\_\.\-\/]+)$')
1138a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1139a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1140a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ReadConfigurationInto(path, sections, defs):
1141a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  current_section = Section(Constant(True))
1142a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sections.append(current_section)
1143a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  prefix = []
1144a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for line in utils.ReadLinesFrom(path):
1145a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    header_match = HEADER_PATTERN.match(line)
1146a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if header_match:
1147a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      condition_str = header_match.group(1).strip()
1148a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      condition = ParseCondition(condition_str)
1149a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      new_section = Section(condition)
1150a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sections.append(new_section)
1151a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      current_section = new_section
1152a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      continue
1153a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    rule_match = RULE_PATTERN.match(line)
1154a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if rule_match:
1155a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      path = prefix + SplitPath(rule_match.group(1).strip())
1156a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value_str = rule_match.group(2).strip()
1157a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value = ParseCondition(value_str)
1158a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not value:
1159a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
1160a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      current_section.AddRule(Rule(rule_match.group(1), path, value))
1161a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      continue
1162a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    def_match = DEF_PATTERN.match(line)
1163a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if def_match:
1164a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      name = def_match.group(1).lower()
1165a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      value = ParseCondition(def_match.group(2).strip())
1166a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not value:
1167a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
1168a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      defs[name] = value
1169a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      continue
1170a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    prefix_match = PREFIX_PATTERN.match(line)
1171a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if prefix_match:
1172a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      prefix = SplitPath(prefix_match.group(1).strip())
1173a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      continue
1174a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "Malformed line: '%s'." % line
1175a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return False
1176a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return True
1177a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1178a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1179a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# ---------------
1180a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# --- M a i n ---
1181a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block# ---------------
1182a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1183a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1184a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockARCH_GUESS = utils.GuessArchitecture()
1185589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben MurdochTIMEOUT_DEFAULT = 60;
1186a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1187a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1188a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef BuildOptions():
1189a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result = optparse.OptionParser()
1190a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-m", "--mode", help="The test modes in which to run (comma-separated)",
1191a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default='release')
1192a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-v", "--verbose", help="Verbose output",
1193a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1194a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-S", dest="scons_flags", help="Flag to pass through to scons",
1195a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=[], action="append")
1196a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-p", "--progress",
1197a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      help="The style of progress indicator (verbose, dots, color, mono)",
1198a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      choices=PROGRESS_INDICATORS.keys(), default="mono")
1199a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--no-build", help="Don't build requirements",
1200a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1201a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--build-only", help="Only build requirements, don't run the tests",
1202a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
120369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  result.add_option("--build-system", help="Build system in use (scons or gyp)",
120469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      default='scons')
1205a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--report", help="Print a summary of the tests to be run",
1206a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
12073ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  result.add_option("--download-data", help="Download missing test suite data",
12083ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      default=False, action="store_true")
1209a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-s", "--suite", help="A test suite",
1210a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=[], action="append")
1211a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-t", "--timeout", help="Timeout in seconds",
1212589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      default=-1, type="int")
1213a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--arch", help='The architecture to run tests for',
1214a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default='none')
1215d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  result.add_option("--snapshot", help="Run the tests with snapshot turned on",
1216d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block      default=False, action="store_true")
1217a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--simulator", help="Run tests with architecture simulator",
1218a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default='none')
1219a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--special-command", default=None)
1220a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--valgrind", help="Run tests through valgrind",
1221a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1222a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--cat", help="Print the source of the tests",
1223a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1224a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--warn-unused", help="Report unused rules",
1225a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1226a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("-j", help="The number of parallel tasks to run",
1227a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=1, type="int")
1228a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--time", help="Print timing information after running",
1229a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      default=False, action="store_true")
1230a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--suppress-dialogs", help="Suppress Windows dialogs for crashing tests",
1231a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        dest="suppress_dialogs", default=True, action="store_true")
1232a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result.add_option("--no-suppress-dialogs", help="Display Windows dialogs for crashing tests",
1233a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        dest="suppress_dialogs", action="store_false")
12343ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  result.add_option("--mips-arch-variant", help="mips architecture variant: mips32r1/mips32r2", default="mips32r2");
123569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  result.add_option("--shell", help="Path to V8 shell", default="d8")
123644f0eee88ff00398ff7f715fab053374d808c90dSteve Block  result.add_option("--isolates", help="Whether to test isolates", default=False, action="store_true")
1237b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--store-unexpected-output",
123880d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      help="Store the temporary JS files from tests that fails",
123980d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      dest="store_unexpected_output", default=True, action="store_true")
1240b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--no-store-unexpected-output",
124180d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      help="Deletes the temporary JS files from tests that fails",
124280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen      dest="store_unexpected_output", action="store_false")
1243b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--stress-only",
1244b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    help="Only run tests with --always-opt --stress-opt",
1245b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    default=False, action="store_true")
1246b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--nostress",
1247b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    help="Don't run crankshaft --always-opt --stress-op test",
1248b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    default=False, action="store_true")
1249b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--crankshaft",
1250b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    help="Run with the --crankshaft flag",
1251b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    default=False, action="store_true")
1252b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  result.add_option("--shard-count",
1253b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    help="Split testsuites into this number of shards",
1254b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    default=1, type="int")
1255b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  result.add_option("--shard-run",
1256b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    help="Run this shard from the split up tests.",
1257b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch                    default=1, type="int")
1258b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  result.add_option("--noprof", help="Disable profiling support",
1259b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch                    default=False)
1260a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result
1261a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1262a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1263a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef ProcessOptions(options):
1264a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  global VERBOSE
1265a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  VERBOSE = options.verbose
1266a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  options.mode = options.mode.split(',')
1267a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for mode in options.mode:
1268a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not mode in ['debug', 'release']:
1269a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "Unknown mode %s" % mode
1270a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return False
1271a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.simulator != 'none':
1272a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # Simulator argument was set. Make sure arch and simulator agree.
1273a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if options.simulator != options.arch:
1274a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if options.arch == 'none':
1275a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        options.arch = options.simulator
1276a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
1277a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        print "Architecture %s does not match sim %s" %(options.arch, options.simulator)
1278a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return False
1279a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # Ensure that the simulator argument is handed down to scons.
1280a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    options.scons_flags.append("simulator=" + options.simulator)
1281a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
1282a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # If options.arch is not set by the command line and no simulator setting
1283a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # was found, set the arch to the guess.
1284a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if options.arch == 'none':
1285a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      options.arch = ARCH_GUESS
1286a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    options.scons_flags.append("arch=" + options.arch)
1287589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  # Simulators are slow, therefore allow a longer default timeout.
1288589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch  if options.timeout == -1:
1289589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    if options.arch == 'arm' or options.arch == 'mips':
1290589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      options.timeout = 2 * TIMEOUT_DEFAULT;
1291589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch    else:
1292589d6979ff2ef66fca2d8fa51404c369ca5e9250Ben Murdoch      options.timeout = TIMEOUT_DEFAULT;
1293d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block  if options.snapshot:
1294d0582a6c46733687d045e4188a1bcd0123c758a1Steve Block    options.scons_flags.append("snapshot=on")
1295b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  global VARIANT_FLAGS
12963ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if options.mips_arch_variant:
12973ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    options.scons_flags.append("mips_arch_variant=" + options.mips_arch_variant)
12983ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1299b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if options.stress_only:
1300b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    VARIANT_FLAGS = [['--stress-opt', '--always-opt']]
1301b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if options.nostress:
1302b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    VARIANT_FLAGS = [[],['--nocrankshaft']]
1303b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if options.crankshaft:
1304b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    if options.special_command:
1305b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch      options.special_command += " --crankshaft"
1306b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    else:
130769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      options.special_command = "@ --crankshaft"
130869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if options.shell.endswith("d8"):
13093fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    if options.special_command:
13103fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch      options.special_command += " --test"
13113fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch    else:
131269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      options.special_command = "@ --test"
1313b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch  if options.noprof:
1314b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    options.scons_flags.append("prof=off")
1315b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch    options.scons_flags.append("profilingsupport=off")
131669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if options.build_system == 'gyp':
131769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    if options.build_only:
131869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      print "--build-only not supported for gyp, please build manually."
131969a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch      options.build_only = False
1320a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return True
1321a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1322a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
132369a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdochdef DoSkip(case):
132469a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  return (SKIP in case.outcomes) or (SLOW in case.outcomes)
132569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
132669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
1327a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockREPORT_TEMPLATE = """\
1328a7e24c173cf37484693b9abb38e494fa7bd7baebSteve BlockTotal: %(total)i tests
1329a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * %(skipped)4d tests will be skipped
133069a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch * %(timeout)4d tests are expected to timeout sometimes
1331a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * %(nocrash)4d tests are expected to be flaky but not crash
1332a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * %(pass)4d tests are expected to pass
1333a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * %(fail_ok)4d tests are expected to fail that we won't fix
1334a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block * %(fail)4d tests are expected to fail that we should fix\
1335a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block"""
1336a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1337a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef PrintReport(cases):
1338a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsFlaky(o):
1339a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return (PASS in o) and (FAIL in o) and (not CRASH in o) and (not OKAY in o)
1340a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsFailOk(o):
1341a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return (len(o) == 2) and (FAIL in o) and (OKAY in o)
134269a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  unskipped = [c for c in cases if not DoSkip(c)]
1343a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  print REPORT_TEMPLATE % {
1344a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'total': len(cases),
1345a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'skipped': len(cases) - len(unskipped),
134669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    'timeout': len([t for t in unskipped if TIMEOUT in t.outcomes]),
1347a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'nocrash': len([t for t in unskipped if IsFlaky(t.outcomes)]),
1348a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'pass': len([t for t in unskipped if list(t.outcomes) == [PASS]]),
1349a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'fail_ok': len([t for t in unskipped if IsFailOk(t.outcomes)]),
1350a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    'fail': len([t for t in unskipped if list(t.outcomes) == [FAIL]])
1351a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  }
1352a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1353a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1354a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockclass Pattern(object):
1355a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1356a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __init__(self, pattern):
1357a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.pattern = pattern
1358a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    self.compiled = None
1359a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1360a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def match(self, str):
1361a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if not self.compiled:
1362a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      pattern = "^" + self.pattern.replace('*', '.*') + "$"
1363a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      self.compiled = re.compile(pattern)
1364a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.compiled.match(str)
1365a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1366a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def __str__(self):
1367a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return self.pattern
1368a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1369a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1370a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef SplitPath(s):
1371a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  stripped = [ c.strip() for c in s.split('/') ]
1372a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return [ Pattern(s) for s in stripped if len(s) > 0 ]
1373a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1374a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1375a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef GetSpecialCommandProcessor(value):
1376a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if (not value) or (value.find('@') == -1):
1377a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    def ExpandCommand(args):
1378a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return args
1379a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return ExpandCommand
1380a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
1381a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    pos = value.find('@')
1382a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    import urllib
1383a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    prefix = urllib.unquote(value[:pos]).split()
1384a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    suffix = urllib.unquote(value[pos+1:]).split()
1385a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    def ExpandCommand(args):
1386a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return prefix + args + suffix
1387a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return ExpandCommand
1388a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1389a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
13908b112d2025046f85ef7f6be087c6129c872ebad2Ben MurdochBUILT_IN_TESTS = ['mjsunit', 'cctest', 'message', 'preparser']
1391a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1392a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1393a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef GetSuites(test_root):
1394a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  def IsSuite(path):
1395a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return isdir(path) and exists(join(path, 'testcfg.py'))
1396a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return [ f for f in os.listdir(test_root) if IsSuite(join(test_root, f)) ]
1397a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1398a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1399a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef FormatTime(d):
1400a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  millis = round(d * 1000) % 1000
1401a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return time.strftime("%M:%S.", time.gmtime(d)) + ("%03i" % millis)
1402a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1403b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdochdef ShardTests(tests, options):
1404b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if options.shard_count < 2:
1405b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    return tests
1406b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  if options.shard_run < 1 or options.shard_run > options.shard_count:
1407b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    print "shard-run not a valid number, should be in [1:shard-count]"
1408b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    print "defaulting back to running all tests"
1409b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    return tests
1410257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch  count = 0
1411b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  shard = []
1412b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  for test in tests:
1413b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    if count % options.shard_count == options.shard_run - 1:
1414257744e915dfc84d6d07a6b2accf8402d9ffc708Ben Murdoch      shard.append(test)
1415b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch    count += 1
1416b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch  return shard
1417a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1418a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockdef Main():
1419a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  parser = BuildOptions()
1420a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  (options, args) = parser.parse_args()
1421a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not ProcessOptions(options):
1422a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    parser.print_help()
1423a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return 1
1424a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1425a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  workspace = abspath(join(dirname(sys.argv[0]), '..'))
1426a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  suites = GetSuites(join(workspace, 'test'))
1427a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  repositories = [TestRepository(join(workspace, 'test', name)) for name in suites]
1428a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  repositories += [TestRepository(a) for a in options.suite]
1429a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1430a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  root = LiteralTestSuite(repositories)
1431a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if len(args) == 0:
1432a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    paths = [SplitPath(t) for t in BUILT_IN_TESTS]
1433a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
1434a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    paths = [ ]
1435a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for arg in args:
1436a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      path = SplitPath(arg)
1437a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      paths.append(path)
1438a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1439a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # Check for --valgrind option. If enabled, we overwrite the special
1440a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # command flag with a command that uses the run-valgrind.py script.
1441a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.valgrind:
1442a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    run_valgrind = join(workspace, "tools", "run-valgrind.py")
1443a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    options.special_command = "python -u " + run_valgrind + " @"
1444a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
144569a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if options.build_system == 'gyp':
144669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    SUFFIX['debug'] = ''
144769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
1448a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  shell = abspath(options.shell)
1449a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  buildspace = dirname(shell)
145080d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1451a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  context = Context(workspace, buildspace, VERBOSE,
1452a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    shell,
1453a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    options.timeout,
1454a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block                    GetSpecialCommandProcessor(options.special_command),
145580d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    options.suppress_dialogs,
145680d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen                    options.store_unexpected_output)
1457a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # First build the required targets
1458a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if not options.no_build:
1459a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    reqs = [ ]
1460a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for path in paths:
1461a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      reqs += root.GetBuildRequirements(path, context)
1462a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    reqs = list(set(reqs))
1463a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    if len(reqs) > 0:
1464a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if options.j != 1:
1465a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        options.scons_flags += ['-j', str(options.j)]
1466a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if not BuildRequirements(context, reqs, options.mode, options.scons_flags):
1467a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        return 1
1468a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1469a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # Just return if we are only building the targets for running the tests.
1470a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.build_only:
1471a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return 0
147280d68eab642096c1a48b6474d6ec33064b0ad1f5Kristian Monsen
1473a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # Get status for tests
1474a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sections = [ ]
1475a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  defs = { }
1476a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  root.GetTestStatus(context, sections, defs)
1477a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  config = Configuration(sections, defs)
1478a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
14793ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  # Download missing test suite data if requested.
14803ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch  if options.download_data:
14813ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch    for path in paths:
14823ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch      root.DownloadData(path, context)
14833ef787dbeca8a5fb1086949cda830dccee07bfbdBen Murdoch
1484a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  # List the tests
1485a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  all_cases = [ ]
1486a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  all_unused = [ ]
1487a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  unclassified_tests = [ ]
1488a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  globally_unused_rules = None
1489a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  for path in paths:
1490a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for mode in options.mode:
1491a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      env = {
1492a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        'mode': mode,
1493a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        'system': utils.GuessOS(),
1494a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        'arch': options.arch,
1495b0fe1620dcb4135ac3ab2d66ff93072373911299Ben Murdoch        'simulator': options.simulator,
14963fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        'crankshaft': options.crankshaft,
14973fb3ca8c7ca439d408449a395897395c0faae8d1Ben Murdoch        'isolates': options.isolates
1498a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      }
149944f0eee88ff00398ff7f715fab053374d808c90dSteve Block      test_list = root.ListTests([], path, context, mode, [])
1500a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      unclassified_tests += test_list
1501a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      (cases, unused_rules, all_outcomes) = config.ClassifyTests(test_list, env)
1502a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if globally_unused_rules is None:
1503a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        globally_unused_rules = set(unused_rules)
1504a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
1505a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        globally_unused_rules = globally_unused_rules.intersection(unused_rules)
1506b8e0da25ee8efac3bb05cd6b2730aafbd96119f4Ben Murdoch      all_cases += ShardTests(cases, options)
1507a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      all_unused.append(unused_rules)
1508a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1509a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.cat:
1510a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    visited = set()
1511a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for test in unclassified_tests:
1512a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      key = tuple(test.path)
1513a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      if key in visited:
1514a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        continue
1515a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      visited.add(key)
1516a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "--- begin source: %s ---" % test.GetLabel()
1517a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      source = test.GetSource().strip()
1518a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print source
1519a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "--- end source: %s ---" % test.GetLabel()
1520a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return 0
1521a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1522a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.warn_unused:
1523a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for rule in globally_unused_rules:
1524a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "Rule for '%s' was not used." % '/'.join([str(s) for s in rule.path])
1525a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
152669a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch  if not options.isolates:
152769a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch    all_cases = [c for c in all_cases if not c.TestsIsolates()]
152869a99ed0b2b2ef69d393c371b03db3a98aaf880eBen Murdoch
1529a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.report:
1530a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    PrintReport(all_cases)
1531a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1532a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  result = None
1533e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  cases_to_run = [ c for c in all_cases if not DoSkip(c) ]
1534e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke  if len(cases_to_run) == 0:
1535a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print "No tests to run."
1536a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    return 0
1537a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  else:
1538a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    try:
1539a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      start = time.time()
1540e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke      if RunTestCases(cases_to_run, options.progress, options.j):
1541a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        result = 0
1542a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      else:
1543a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block        result = 1
1544a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      duration = time.time() - start
1545a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    except KeyboardInterrupt:
1546a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      print "Interrupted"
1547a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      return 1
1548a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1549a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  if options.time:
1550a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # Write the times to stderr to make it easy to separate from the
1551a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    # test output.
1552a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    print
1553a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    sys.stderr.write("--- Total time: %s ---\n" % FormatTime(duration))
1554e46be819fca9468a0cd4e74859ce0f778eb8ca60Leon Clarke    timed_tests = [ t.case for t in cases_to_run if not t.case.duration is None ]
1555a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    timed_tests.sort(lambda a, b: a.CompareTime(b))
1556a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    index = 1
1557a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block    for entry in timed_tests[:20]:
1558a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      t = FormatTime(entry.duration)
1559a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      sys.stderr.write("%4i (%s) %s\n" % (index, t, entry.GetLabel()))
1560a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block      index += 1
1561a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1562a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  return result
1563a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1564a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block
1565a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Blockif __name__ == '__main__':
1566a7e24c173cf37484693b9abb38e494fa7bd7baebSteve Block  sys.exit(Main())
1567