Home | History | Annotate | Download | only in local
      1 # Copyright 2012 the V8 project authors. All rights reserved.
      2 # Redistribution and use in source and binary forms, with or without
      3 # modification, are permitted provided that the following conditions are
      4 # met:
      5 #
      6 #     * Redistributions of source code must retain the above copyright
      7 #       notice, this list of conditions and the following disclaimer.
      8 #     * Redistributions in binary form must reproduce the above
      9 #       copyright notice, this list of conditions and the following
     10 #       disclaimer in the documentation and/or other materials provided
     11 #       with the distribution.
     12 #     * Neither the name of Google Inc. nor the names of its
     13 #       contributors may be used to endorse or promote products derived
     14 #       from this software without specific prior written permission.
     15 #
     16 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 
     29 import sys
     30 import time
     31 
     32 from . import junit_output
     33 
     34 def EscapeCommand(command):
     35   parts = []
     36   for part in command:
     37     if ' ' in part:
     38       # Escape spaces.  We may need to escape more characters for this
     39       # to work properly.
     40       parts.append('"%s"' % part)
     41     else:
     42       parts.append(part)
     43   return " ".join(parts)
     44 
     45 
     46 class ProgressIndicator(object):
     47 
     48   def __init__(self):
     49     self.runner = None
     50 
     51   def Starting(self):
     52     pass
     53 
     54   def Done(self):
     55     pass
     56 
     57   def AboutToRun(self, test):
     58     pass
     59 
     60   def HasRun(self, test, has_unexpected_output):
     61     pass
     62 
     63   def PrintFailureHeader(self, test):
     64     if test.suite.IsNegativeTest(test):
     65       negative_marker = '[negative] '
     66     else:
     67       negative_marker = ''
     68     print "=== %(label)s %(negative)s===" % {
     69       'label': test.GetLabel(),
     70       'negative': negative_marker
     71     }
     72 
     73 
     74 class SimpleProgressIndicator(ProgressIndicator):
     75   """Abstract base class for {Verbose,Dots}ProgressIndicator"""
     76 
     77   def Starting(self):
     78     print 'Running %i tests' % self.runner.total
     79 
     80   def Done(self):
     81     print
     82     for failed in self.runner.failed:
     83       self.PrintFailureHeader(failed)
     84       if failed.output.stderr:
     85         print "--- stderr ---"
     86         print failed.output.stderr.strip()
     87       if failed.output.stdout:
     88         print "--- stdout ---"
     89         print failed.output.stdout.strip()
     90       print "Command: %s" % EscapeCommand(self.runner.GetCommand(failed))
     91       if failed.output.HasCrashed():
     92         print "--- CRASHED ---"
     93       if failed.output.HasTimedOut():
     94         print "--- TIMEOUT ---"
     95     if len(self.runner.failed) == 0:
     96       print "==="
     97       print "=== All tests succeeded"
     98       print "==="
     99     else:
    100       print
    101       print "==="
    102       print "=== %i tests failed" % len(self.runner.failed)
    103       if self.runner.crashed > 0:
    104         print "=== %i tests CRASHED" % self.runner.crashed
    105       print "==="
    106 
    107 
    108 class VerboseProgressIndicator(SimpleProgressIndicator):
    109 
    110   def AboutToRun(self, test):
    111     print 'Starting %s...' % test.GetLabel()
    112     sys.stdout.flush()
    113 
    114   def HasRun(self, test, has_unexpected_output):
    115     if has_unexpected_output:
    116       if test.output.HasCrashed():
    117         outcome = 'CRASH'
    118       else:
    119         outcome = 'FAIL'
    120     else:
    121       outcome = 'pass'
    122     print 'Done running %s: %s' % (test.GetLabel(), outcome)
    123 
    124 
    125 class DotsProgressIndicator(SimpleProgressIndicator):
    126 
    127   def HasRun(self, test, has_unexpected_output):
    128     total = self.runner.succeeded + len(self.runner.failed)
    129     if (total > 1) and (total % 50 == 1):
    130       sys.stdout.write('\n')
    131     if has_unexpected_output:
    132       if test.output.HasCrashed():
    133         sys.stdout.write('C')
    134         sys.stdout.flush()
    135       elif test.output.HasTimedOut():
    136         sys.stdout.write('T')
    137         sys.stdout.flush()
    138       else:
    139         sys.stdout.write('F')
    140         sys.stdout.flush()
    141     else:
    142       sys.stdout.write('.')
    143       sys.stdout.flush()
    144 
    145 
    146 class CompactProgressIndicator(ProgressIndicator):
    147   """Abstract base class for {Color,Monochrome}ProgressIndicator"""
    148 
    149   def __init__(self, templates):
    150     super(CompactProgressIndicator, self).__init__()
    151     self.templates = templates
    152     self.last_status_length = 0
    153     self.start_time = time.time()
    154 
    155   def Done(self):
    156     self.PrintProgress('Done')
    157     print ""  # Line break.
    158 
    159   def AboutToRun(self, test):
    160     self.PrintProgress(test.GetLabel())
    161 
    162   def HasRun(self, test, has_unexpected_output):
    163     if has_unexpected_output:
    164       self.ClearLine(self.last_status_length)
    165       self.PrintFailureHeader(test)
    166       stdout = test.output.stdout.strip()
    167       if len(stdout):
    168         print self.templates['stdout'] % stdout
    169       stderr = test.output.stderr.strip()
    170       if len(stderr):
    171         print self.templates['stderr'] % stderr
    172       print "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
    173       if test.output.HasCrashed():
    174         print "exit code: %d" % test.output.exit_code
    175         print "--- CRASHED ---"
    176       if test.output.HasTimedOut():
    177         print "--- TIMEOUT ---"
    178 
    179   def Truncate(self, string, length):
    180     if length and (len(string) > (length - 3)):
    181       return string[:(length - 3)] + "..."
    182     else:
    183       return string
    184 
    185   def PrintProgress(self, name):
    186     self.ClearLine(self.last_status_length)
    187     elapsed = time.time() - self.start_time
    188     status = self.templates['status_line'] % {
    189       'passed': self.runner.succeeded,
    190       'remaining': (((self.runner.total - self.runner.remaining) * 100) //
    191                     self.runner.total),
    192       'failed': len(self.runner.failed),
    193       'test': name,
    194       'mins': int(elapsed) / 60,
    195       'secs': int(elapsed) % 60
    196     }
    197     status = self.Truncate(status, 78)
    198     self.last_status_length = len(status)
    199     print status,
    200     sys.stdout.flush()
    201 
    202 
    203 class ColorProgressIndicator(CompactProgressIndicator):
    204 
    205   def __init__(self):
    206     templates = {
    207       'status_line': ("[%(mins)02i:%(secs)02i|"
    208                       "\033[34m%%%(remaining) 4d\033[0m|"
    209                       "\033[32m+%(passed) 4d\033[0m|"
    210                       "\033[31m-%(failed) 4d\033[0m]: %(test)s"),
    211       'stdout': "\033[1m%s\033[0m",
    212       'stderr': "\033[31m%s\033[0m",
    213     }
    214     super(ColorProgressIndicator, self).__init__(templates)
    215 
    216   def ClearLine(self, last_line_length):
    217     print "\033[1K\r",
    218 
    219 
    220 class MonochromeProgressIndicator(CompactProgressIndicator):
    221 
    222   def __init__(self):
    223     templates = {
    224       'status_line': ("[%(mins)02i:%(secs)02i|%%%(remaining) 4d|"
    225                       "+%(passed) 4d|-%(failed) 4d]: %(test)s"),
    226       'stdout': '%s',
    227       'stderr': '%s',
    228     }
    229     super(MonochromeProgressIndicator, self).__init__(templates)
    230 
    231   def ClearLine(self, last_line_length):
    232     print ("\r" + (" " * last_line_length) + "\r"),
    233 
    234 
    235 class JUnitTestProgressIndicator(ProgressIndicator):
    236 
    237   def __init__(self, progress_indicator, junitout, junittestsuite):
    238     self.progress_indicator = progress_indicator
    239     self.outputter = junit_output.JUnitTestOutput(junittestsuite)
    240     if junitout:
    241       self.outfile = open(junitout, "w")
    242     else:
    243       self.outfile = sys.stdout
    244 
    245   def Starting(self):
    246     self.progress_indicator.runner = self.runner
    247     self.progress_indicator.Starting()
    248 
    249   def Done(self):
    250     self.progress_indicator.Done()
    251     self.outputter.FinishAndWrite(self.outfile)
    252     if self.outfile != sys.stdout:
    253       self.outfile.close()
    254 
    255   def AboutToRun(self, test):
    256     self.progress_indicator.AboutToRun(test)
    257 
    258   def HasRun(self, test, has_unexpected_output):
    259     self.progress_indicator.HasRun(test, has_unexpected_output)
    260     fail_text = ""
    261     if has_unexpected_output:
    262       stdout = test.output.stdout.strip()
    263       if len(stdout):
    264         fail_text += "stdout:\n%s\n" % stdout
    265       stderr = test.output.stderr.strip()
    266       if len(stderr):
    267         fail_text += "stderr:\n%s\n" % stderr
    268       fail_text += "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
    269       if test.output.HasCrashed():
    270         fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code
    271       if test.output.HasTimedOut():
    272         fail_text += "--- TIMEOUT ---"
    273     self.outputter.HasRunTest(
    274         [test.GetLabel()] + self.runner.context.mode_flags + test.flags,
    275         test.duration,
    276         fail_text)
    277 
    278 
    279 PROGRESS_INDICATORS = {
    280   'verbose': VerboseProgressIndicator,
    281   'dots': DotsProgressIndicator,
    282   'color': ColorProgressIndicator,
    283   'mono': MonochromeProgressIndicator
    284 }
    285