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 "exit code: %d" % failed.output.exit_code
     93         print "--- CRASHED ---"
     94       if failed.output.HasTimedOut():
     95         print "--- TIMEOUT ---"
     96     if len(self.runner.failed) == 0:
     97       print "==="
     98       print "=== All tests succeeded"
     99       print "==="
    100     else:
    101       print
    102       print "==="
    103       print "=== %i tests failed" % len(self.runner.failed)
    104       if self.runner.crashed > 0:
    105         print "=== %i tests CRASHED" % self.runner.crashed
    106       print "==="
    107 
    108 
    109 class VerboseProgressIndicator(SimpleProgressIndicator):
    110 
    111   def AboutToRun(self, test):
    112     print 'Starting %s...' % test.GetLabel()
    113     sys.stdout.flush()
    114 
    115   def HasRun(self, test, has_unexpected_output):
    116     if has_unexpected_output:
    117       if test.output.HasCrashed():
    118         outcome = 'CRASH'
    119       else:
    120         outcome = 'FAIL'
    121     else:
    122       outcome = 'pass'
    123     print 'Done running %s: %s' % (test.GetLabel(), outcome)
    124 
    125 
    126 class DotsProgressIndicator(SimpleProgressIndicator):
    127 
    128   def HasRun(self, test, has_unexpected_output):
    129     total = self.runner.succeeded + len(self.runner.failed)
    130     if (total > 1) and (total % 50 == 1):
    131       sys.stdout.write('\n')
    132     if has_unexpected_output:
    133       if test.output.HasCrashed():
    134         sys.stdout.write('C')
    135         sys.stdout.flush()
    136       elif test.output.HasTimedOut():
    137         sys.stdout.write('T')
    138         sys.stdout.flush()
    139       else:
    140         sys.stdout.write('F')
    141         sys.stdout.flush()
    142     else:
    143       sys.stdout.write('.')
    144       sys.stdout.flush()
    145 
    146 
    147 class CompactProgressIndicator(ProgressIndicator):
    148   """Abstract base class for {Color,Monochrome}ProgressIndicator"""
    149 
    150   def __init__(self, templates):
    151     super(CompactProgressIndicator, self).__init__()
    152     self.templates = templates
    153     self.last_status_length = 0
    154     self.start_time = time.time()
    155 
    156   def Done(self):
    157     self.PrintProgress('Done')
    158     print ""  # Line break.
    159 
    160   def AboutToRun(self, test):
    161     self.PrintProgress(test.GetLabel())
    162 
    163   def HasRun(self, test, has_unexpected_output):
    164     if has_unexpected_output:
    165       self.ClearLine(self.last_status_length)
    166       self.PrintFailureHeader(test)
    167       stdout = test.output.stdout.strip()
    168       if len(stdout):
    169         print self.templates['stdout'] % stdout
    170       stderr = test.output.stderr.strip()
    171       if len(stderr):
    172         print self.templates['stderr'] % stderr
    173       print "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
    174       if test.output.HasCrashed():
    175         print "exit code: %d" % test.output.exit_code
    176         print "--- CRASHED ---"
    177       if test.output.HasTimedOut():
    178         print "--- TIMEOUT ---"
    179 
    180   def Truncate(self, string, length):
    181     if length and (len(string) > (length - 3)):
    182       return string[:(length - 3)] + "..."
    183     else:
    184       return string
    185 
    186   def PrintProgress(self, name):
    187     self.ClearLine(self.last_status_length)
    188     elapsed = time.time() - self.start_time
    189     status = self.templates['status_line'] % {
    190       'passed': self.runner.succeeded,
    191       'remaining': (((self.runner.total - self.runner.remaining) * 100) //
    192                     self.runner.total),
    193       'failed': len(self.runner.failed),
    194       'test': name,
    195       'mins': int(elapsed) / 60,
    196       'secs': int(elapsed) % 60
    197     }
    198     status = self.Truncate(status, 78)
    199     self.last_status_length = len(status)
    200     print status,
    201     sys.stdout.flush()
    202 
    203 
    204 class ColorProgressIndicator(CompactProgressIndicator):
    205 
    206   def __init__(self):
    207     templates = {
    208       'status_line': ("[%(mins)02i:%(secs)02i|"
    209                       "\033[34m%%%(remaining) 4d\033[0m|"
    210                       "\033[32m+%(passed) 4d\033[0m|"
    211                       "\033[31m-%(failed) 4d\033[0m]: %(test)s"),
    212       'stdout': "\033[1m%s\033[0m",
    213       'stderr': "\033[31m%s\033[0m",
    214     }
    215     super(ColorProgressIndicator, self).__init__(templates)
    216 
    217   def ClearLine(self, last_line_length):
    218     print "\033[1K\r",
    219 
    220 
    221 class MonochromeProgressIndicator(CompactProgressIndicator):
    222 
    223   def __init__(self):
    224     templates = {
    225       'status_line': ("[%(mins)02i:%(secs)02i|%%%(remaining) 4d|"
    226                       "+%(passed) 4d|-%(failed) 4d]: %(test)s"),
    227       'stdout': '%s',
    228       'stderr': '%s',
    229     }
    230     super(MonochromeProgressIndicator, self).__init__(templates)
    231 
    232   def ClearLine(self, last_line_length):
    233     print ("\r" + (" " * last_line_length) + "\r"),
    234 
    235 
    236 class JUnitTestProgressIndicator(ProgressIndicator):
    237 
    238   def __init__(self, progress_indicator, junitout, junittestsuite):
    239     self.progress_indicator = progress_indicator
    240     self.outputter = junit_output.JUnitTestOutput(junittestsuite)
    241     if junitout:
    242       self.outfile = open(junitout, "w")
    243     else:
    244       self.outfile = sys.stdout
    245 
    246   def Starting(self):
    247     self.progress_indicator.runner = self.runner
    248     self.progress_indicator.Starting()
    249 
    250   def Done(self):
    251     self.progress_indicator.Done()
    252     self.outputter.FinishAndWrite(self.outfile)
    253     if self.outfile != sys.stdout:
    254       self.outfile.close()
    255 
    256   def AboutToRun(self, test):
    257     self.progress_indicator.AboutToRun(test)
    258 
    259   def HasRun(self, test, has_unexpected_output):
    260     self.progress_indicator.HasRun(test, has_unexpected_output)
    261     fail_text = ""
    262     if has_unexpected_output:
    263       stdout = test.output.stdout.strip()
    264       if len(stdout):
    265         fail_text += "stdout:\n%s\n" % stdout
    266       stderr = test.output.stderr.strip()
    267       if len(stderr):
    268         fail_text += "stderr:\n%s\n" % stderr
    269       fail_text += "Command: %s" % EscapeCommand(self.runner.GetCommand(test))
    270       if test.output.HasCrashed():
    271         fail_text += "exit code: %d\n--- CRASHED ---" % test.output.exit_code
    272       if test.output.HasTimedOut():
    273         fail_text += "--- TIMEOUT ---"
    274     self.outputter.HasRunTest(
    275         [test.GetLabel()] + self.runner.context.mode_flags + test.flags,
    276         test.duration,
    277         fail_text)
    278 
    279 
    280 PROGRESS_INDICATORS = {
    281   'verbose': VerboseProgressIndicator,
    282   'dots': DotsProgressIndicator,
    283   'color': ColorProgressIndicator,
    284   'mono': MonochromeProgressIndicator
    285 }
    286