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