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