1 26 27 package net.sourceforge.groboutils.codecoverage.v2.ant; 28 29 import java.text.NumberFormat ; 30 import java.util.Enumeration ; 31 import java.util.StringTokenizer ; 32 import java.util.Vector ; 33 34 import org.apache.tools.ant.BuildException; 35 import org.apache.tools.ant.Project; 36 import org.w3c.dom.Document ; 37 import org.w3c.dom.Element ; 38 import org.w3c.dom.NodeList ; 39 40 41 42 50 public class FailOnReportStyle implements IReportStyle 51 { 52 private Vector includeExcludeSet = new Vector (); 53 private String failureProperty = null; 54 private double minPercent = 80.0; 55 56 private int markCount = 0; 57 private int coverCount = 0; 58 59 private static final NumberFormat DOUBLE_FORMATTER = 60 NumberFormat.getInstance(); 61 static { 62 DOUBLE_FORMATTER.setMaximumFractionDigits( 2 ); 63 } 64 65 66 public static class IncludeAndExclude 67 { 68 String value = null; 69 boolean module = false; 70 boolean corp = false; 71 boolean isInclude = true; 72 73 public void setModule( String s ) 74 { 75 this.module = true; 76 this.value = s; 77 } 78 79 public void setClass( String f ) 80 { 81 this.corp = true; 82 this.value = f; 83 } 84 85 86 protected void check() 87 throws BuildException 88 { 89 if (this.module && this.corp) 90 { 91 throw new BuildException( 92 "Only one of 'module' and 'class' attributes can be "+ 93 "specified in an "+this.getType()+" element." ); 94 } 95 if (!this.module && !this.corp) 96 { 97 throw new BuildException( 98 "One of 'module' or 'class' attributes must be "+ 99 "specified in an "+this.getType()+" element." ); 100 } 101 } 102 103 protected String getType() 104 { 105 return (this.isInclude ? "include" : "exclude"); 106 } 107 } 108 109 110 static class ClassFilter 111 { 112 IFilterToken parts[]; 113 114 public ClassFilter( String filter ) 115 throws BuildException 116 { 117 if (filter == null || filter.length() <= 0 || 118 filter.charAt(0) == '.' || filter.indexOf( ".." ) >= 0 || 119 filter.indexOf( "//" ) >= 0 || filter.indexOf( "/." ) >= 0 || 120 filter.indexOf( "./" ) >= 0 || 121 filter.charAt(filter.length()-1) == '.' || 122 filter.charAt(filter.length()-1) == '/') 123 { 124 throw new BuildException( "Invalid class filter '"+filter+"'" ); 125 } 126 if (filter.charAt(0) == '/') 127 { 128 if (filter.length() <= 1) 129 { 130 throw new BuildException( "Invalid class filter '"+filter+"'" ); 131 } 132 filter = filter.substring( 1 ); 133 } 134 135 StringTokenizer st = new StringTokenizer ( filter, "./", false ); 136 Vector v = new Vector (); 137 while (st.hasMoreTokens()) 138 { 139 String s = st.nextToken(); 140 if (s.length() <= 0) 141 { 142 throw new BuildException( 143 "Invalid class filter: no values between delimiters." 144 ); 145 } 146 int len = s.length(); 147 if (s.charAt(0) == '*') 148 { 149 if (len == 1) 150 { 151 v.addElement( ANY_TOKEN ); 152 } 153 else 154 if (len == 2 && s.charAt(1) == '*') 156 { 157 v.addElement( NULL_TOKEN ); 158 } 159 else 160 { 161 s = s.substring( 1 ); 162 if (s.indexOf( '*' ) >= 0) 163 { 164 throw new BuildException( 165 "Invalid class filter: only 1 wildcard may "+ 166 "be present between delimiters." ); 167 } 168 v.addElement( new BeforeFilterToken( s ) ); 169 } 170 } 171 else 172 if (s.charAt( len - 1) == '*') 173 { 174 s = s.substring( 0, len - 1 ); 175 if (s.indexOf( '*' ) >= 0) 176 { 177 throw new BuildException( 178 "Invalid class filter: only 1 wildcard may "+ 179 "be present between delimiters." ); 180 } 181 v.addElement( new EndFilterToken( s ) ); 182 } 183 else 184 { 185 if (s.indexOf( '*' ) > 0) 186 { 187 throw new BuildException( 188 "Invalid class filter: a wildcard may "+ 189 "only be present before and after a text part." ); 190 } 191 v.addElement( new ExactFilterToken( s ) ); 192 } 193 } 194 if (v.size() <= 0) 195 { 196 throw new BuildException( 197 "Invalid class filter: no delimited elements" ); 198 } 199 parts = new IFilterToken[ v.size() ]; 200 v.copyInto( parts ); 201 } 202 203 204 public boolean match( String c ) 205 { 206 if (c == null || c.length() <= 0) 207 { 208 throw new IllegalArgumentException ( "no null args." ); 209 } 210 211 StringTokenizer st = new StringTokenizer ( c, ".", false ); 212 int filterPos = 0; 213 while (st.hasMoreTokens()) 214 { 215 if (filterPos >= this.parts.length) 216 { 217 return false; 218 } 219 String s = st.nextToken(); 220 221 if (this.parts[filterPos] == NULL_TOKEN) 223 { 224 if (filterPos == this.parts.length - 1) 226 { 227 return true; 228 } 229 230 if (this.parts[filterPos+1].match( s )) 232 { 233 filterPos += 2; 236 } 237 } 240 else 241 { 242 if (!this.parts[filterPos++].match( s )) 245 { 246 return false; 247 } 248 } 249 } 250 251 return (filterPos >= this.parts.length); 254 } 255 } 256 257 static interface IFilterToken 260 { 261 public boolean match( String part ); 262 } 263 264 private static class BeforeFilterToken implements IFilterToken 265 { 266 private String m; 267 public BeforeFilterToken( String s ) 268 { 269 this.m = s; 270 } 271 public boolean match( String part ) 272 { 273 return part.endsWith( this.m ); 274 } 275 } 276 277 private static class EndFilterToken implements IFilterToken 278 { 279 private String m; 280 public EndFilterToken( String s ) 281 { 282 this.m = s; 283 } 284 public boolean match( String part ) 285 { 286 return part.startsWith( this.m ); 287 } 288 } 289 290 private static class ExactFilterToken implements IFilterToken 291 { 292 private String m; 293 public ExactFilterToken( String s ) 294 { 295 this.m = s; 296 } 297 public boolean match( String part ) 298 { 299 return part.equals( this.m ); 300 } 301 } 302 303 private static class AnyFilterToken implements IFilterToken 304 { 305 public boolean match( String part ) 306 { 307 return true; 308 } 309 } 310 private static final IFilterToken ANY_TOKEN = new AnyFilterToken(); 311 private static final IFilterToken NULL_TOKEN = new AnyFilterToken(); 312 313 314 315 public void setPercentage( double v ) 316 { 317 this.minPercent = v; 318 } 319 320 321 public void setProperty( String p ) 322 { 323 this.failureProperty = p; 324 } 325 326 327 public void addInclude( IncludeAndExclude iae ) 328 { 329 if (iae != null) 330 { 331 iae.isInclude = true; 332 this.includeExcludeSet.addElement( iae ); 333 } 334 } 335 336 337 public void addExclude( IncludeAndExclude iae ) 338 { 339 if (iae != null) 340 { 341 iae.isInclude = false; 342 this.includeExcludeSet.addElement( iae ); 343 } 344 } 345 346 347 348 349 350 354 public void reportComplete( Project project, Vector errorList ) 355 throws BuildException 356 { 357 double actual = getActualPercentage(); 358 project.log( 359 "Testing for minimal coverage of "+ 360 DOUBLE_FORMATTER.format( this.minPercent )+ 361 ", and found an actual coverage of "+ 362 DOUBLE_FORMATTER.format( actual ), Project.MSG_VERBOSE ); 363 if (actual < this.minPercent) 364 { 365 if (this.failureProperty != null) 367 { 368 project.setNewProperty( this.failureProperty, 369 Double.toString( actual ) ); 370 } 371 errorList.addElement( 372 "Did not have sufficient coverage: requires "+ 373 DOUBLE_FORMATTER.format( this.minPercent ) + 374 ", but found " + DOUBLE_FORMATTER.format( actual ) + "." ); 375 } 376 } 377 378 379 public void generateReport( Project project, Document doc, 380 String moduleName ) 381 throws BuildException 382 { 383 Vector inClass = new Vector (); 384 Vector exClass = new Vector (); 385 Vector inMod = new Vector (); 386 Vector exMod = new Vector (); 387 setupFilters( inClass, exClass, inMod, exMod ); 388 389 if (!"all".equalsIgnoreCase( moduleName ) && 390 !matchModule( moduleName, inMod, exMod )) 391 { 392 return; 393 } 394 395 396 NodeList ccList = doc.getElementsByTagName( "classcoverage" ); 397 for (int ccIndex = 0; ccIndex < ccList.getLength(); ++ccIndex) 398 { 399 Element ccEl = (Element )ccList.item( ccIndex ); 400 401 NodeList coverList = ccEl.getElementsByTagName( "cover" ); 402 for (int coverIndex = 0; coverIndex < coverList.getLength(); 403 ++coverIndex) 404 { 405 Element coverEl = (Element )coverList.item( coverIndex ); 406 NodeList modList = coverEl.getElementsByTagName( 407 "modulecover" ); 408 if (modList != null && modList.getLength() > 0) 409 { 410 for (int modIndex = 0; modIndex < modList.getLength(); 411 ++modIndex) 412 { 413 Element modEl = (Element )modList.item( modIndex ); 414 if (matchModule( modEl.getAttribute( "measure" ), 415 inMod, exMod )) 416 { 417 cover( project, modEl ); 418 } 419 } 420 } 421 else 422 { 423 cover( project, coverEl ); 424 } 425 } 426 } 427 434 435 } 436 437 438 protected void cover( Project project, Element el ) 439 { 440 String coveredS = el.getAttribute( "covered" ); 441 String markedS = el.getAttribute( "total" ); 442 try 443 { 444 int cov = Integer.parseInt( coveredS ); 445 int mar = Integer.parseInt( markedS ); 446 447 if (cov > 0 && mar > 0) 449 { 450 this.coverCount += cov; 451 this.markCount += mar; 452 } 453 } 454 catch (NumberFormatException e) 455 { 456 project.log( "Invalid covered attribute: expected a number.", 457 Project.MSG_VERBOSE ); 458 } 459 } 460 461 462 protected double getActualPercentage() 463 { 464 if (this.markCount == 0) 465 { 466 return 100.0; 467 } 468 return ((double)this.coverCount * 100.0) / (double)this.markCount; 470 } 471 472 473 protected boolean matchModule( String moduleName, 474 Vector inMod, Vector exMod ) 475 { 476 if (!matchModuleInSet( moduleName, inMod )) 478 { 479 return false; 480 } 481 if (matchModuleInSet( moduleName, exMod )) 482 { 483 return false; 484 } 485 return true; 486 } 487 488 489 protected boolean matchModuleInSet( String moduleName, Vector set ) 490 { 491 Enumeration e = set.elements(); 492 while (e.hasMoreElements()) 493 { 494 String m = (String )e.nextElement(); 495 if ("*".equals(m) || moduleName.equalsIgnoreCase( m )) 496 { 497 return true; 498 } 499 } 500 return false; 501 } 502 503 504 protected boolean matchClass( String className, 505 Vector inClass, Vector exClass ) 506 { 507 if (!matchClassInSet( className, inClass )) 508 { 509 return false; 510 } 511 if (matchClassInSet( className, exClass )) 512 { 513 return false; 514 } 515 return true; 516 } 517 518 519 protected boolean matchClassInSet( String className, Vector set ) 520 { 521 Enumeration e = set.elements(); 522 while (e.hasMoreElements()) 523 { 524 ClassFilter cf = (ClassFilter)e.nextElement(); 525 if (cf.match( className )) 526 { 527 return true; 528 } 529 } 530 return false; 531 } 532 533 534 protected void setupFilters( Vector includeClass, Vector excludeClass, 535 Vector includeModule, Vector excludeModule ) 536 throws BuildException 537 { 538 Enumeration e = this.includeExcludeSet.elements(); 539 while (e.hasMoreElements()) 540 { 541 IncludeAndExclude iae = (IncludeAndExclude)e.nextElement(); 542 iae.check(); 543 if (iae.module) 544 { 545 if (iae.isInclude) 546 { 547 includeModule.addElement( iae.value ); 548 } 549 else 550 { 551 excludeModule.addElement( iae.value ); 552 } 553 } 554 else 555 { 557 if (iae.isInclude) 558 { 559 includeClass.addElement( new ClassFilter( iae.value ) ); 560 } 561 else 562 { 563 excludeClass.addElement( new ClassFilter( iae.value ) ); 564 } 565 } 566 } 567 568 if (includeModule.size() <= 0) 571 { 572 includeModule.addElement( "*" ); 573 } 574 if (includeClass.size() <= 0) 575 { 576 includeClass.addElement( new ClassFilter( "**" ) ); 577 } 578 } 579 } 580 581 | Popular Tags |