View Javadoc
1 /*** 2 * Redistribution and use of this software and associated documentation 3 * ("Software"), with or without modification, are permitted provided 4 * that the following conditions are met: 5 * 6 * 1. Redistributions of source code must retain copyright 7 * statements and notices. Redistributions must also contain a 8 * copy of this document. 9 * 10 * 2. Redistributions in binary form must reproduce the 11 * above copyright notice, this list of conditions and the 12 * following disclaimer in the documentation and/or other 13 * materials provided with the distribution. 14 * 15 * 3. The name "Exolab" must not be used to endorse or promote 16 * products derived from this Software without prior written 17 * permission of Exoffice Technologies. For written permission, 18 * please contact tma@netspace.net.au. 19 * 20 * 4. Products derived from this Software may not be called "Exolab" 21 * nor may "Exolab" appear in their names without prior written 22 * permission of Exoffice Technologies. Exolab is a registered 23 * trademark of Exoffice Technologies. 24 * 25 * 5. Due credit should be given to the Exolab Project 26 * (http://www.exolab.org/). 27 * 28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS 29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT 30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 39 * OF THE POSSIBILITY OF SUCH DAMAGE. 40 * 41 * Copyright 2001-2004 (C) Exoffice Technologies Inc. All Rights Reserved. 42 * 43 * $Id: TestCoverage.java,v 1.5 2004/01/31 13:44:24 tanderson Exp $ 44 */ 45 package org.exolab.jmscts.core; 46 47 import java.util.ArrayList; 48 import java.util.HashMap; 49 import java.util.HashSet; 50 import java.util.Iterator; 51 import java.util.List; 52 53 import org.apache.log4j.Category; 54 55 import junit.framework.Test; 56 57 import org.exolab.jmscts.report.Context; 58 import org.exolab.jmscts.report.Coverage; 59 import org.exolab.jmscts.report.CurrentTest; 60 import org.exolab.jmscts.report.Failure; 61 import org.exolab.jmscts.report.ReportHelper; 62 import org.exolab.jmscts.report.RequirementCoverage; 63 import org.exolab.jmscts.report.TestRun; 64 import org.exolab.jmscts.report.TestRuns; 65 import org.exolab.jmscts.requirements.Requirement; 66 import org.exolab.jmscts.requirements.Requirements; 67 68 69 /*** 70 * This class maintains the state of the test suite's coverage of requirements 71 * 72 * @version $Revision: 1.5 $ $Date: 2004/01/31 13:44:24 $ 73 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a> 74 * @see Coverage 75 * @see Requirements 76 */ 77 public class TestCoverage { 78 79 /*** 80 * A map of requirement id's to {@link Coverage} instances 81 */ 82 private HashMap _coverage = new HashMap(); 83 84 /*** 85 * A map of test names to their corresponding TestRuns instances 86 */ 87 private HashMap _testRuns = new HashMap(); 88 89 /*** 90 * A list of failures not associated with any test case 91 */ 92 private List _failures = new ArrayList(); 93 94 /*** 95 * The requirements 96 */ 97 private Requirements _requirements; 98 99 /*** 100 * The current executing test case 101 */ 102 private JMSTestCase _current; 103 104 /*** 105 * The current test run 106 */ 107 private TestRun _currentRun; 108 109 /*** 110 * The logger 111 */ 112 private static final Category log = 113 Category.getInstance(TestCoverage.class); 114 115 116 /*** 117 * Construct an instance with the set of requirements 118 * 119 * @param requirements the requirements 120 */ 121 public TestCoverage(Requirements requirements) { 122 if (requirements == null) { 123 throw new IllegalArgumentException( 124 "Argument 'requirements' is null"); 125 } 126 _requirements = requirements; 127 } 128 129 /*** 130 * Log the start of a test.</br> 131 * NOTE: {@link #begin} may not be invoked if the test setup fails. In 132 * this instance, only {@link #failed} will be invoked 133 * 134 * @param test the test case 135 */ 136 public synchronized void begin(JMSTestCase test) { 137 String[] requirements = test.getRequirements(test.getName()); 138 if (requirements == null || requirements.length == 0) { 139 log.error("Test=" + ReportHelper.getName(test) + " started but " 140 + "is not associated with any requirements"); 141 } else { 142 _current = test; 143 _currentRun = getTest(test, test.getContext()); 144 for (int i = 0; i < requirements.length; ++i) { 145 addCoverage(requirements[i], test); 146 } 147 } 148 } 149 150 /*** 151 * Log the end of a test 152 * 153 * @param test the test that has completed 154 */ 155 public synchronized void end(JMSTestCase test) { 156 _current = null; 157 _currentRun = null; 158 } 159 160 /*** 161 * Log a test case failure 162 * 163 * @param test the test case 164 * @param cause the reason for the failure 165 * @param rootCause the root cause of the failure. May be null 166 */ 167 public synchronized void failed(Test test, Throwable cause, 168 Throwable rootCause) { 169 if (test instanceof JMSTestCase) { 170 addFailure((JMSTestCase) test, cause, rootCause); 171 } else if (test instanceof TestRunner) { 172 addFailure((TestRunner) test, cause, rootCause); 173 } else { 174 addFailure(cause, rootCause); 175 } 176 } 177 178 /*** 179 * Set a requirement as being unsupported 180 * 181 * @param requirementId the requirement identifier 182 */ 183 public synchronized void setUnsupported(String requirementId) { 184 Coverage coverage = (Coverage) _coverage.get(requirementId); 185 if (coverage == null) { 186 log.error("Invalid requirement identifier=" + requirementId); 187 } else { 188 coverage.setSupported(false); 189 } 190 } 191 192 /*** 193 * Returns the coverage of requirements by the test suite 194 * 195 * @return the coverage of requirements by the test suite 196 */ 197 public synchronized RequirementCoverage getCoverage() { 198 RequirementCoverage result = new RequirementCoverage(); 199 200 if (_current != null) { 201 // if a test case is currently executing, return its state 202 CurrentTest current = new CurrentTest(); 203 current.setTest(ReportHelper.getName(_current)); 204 current.setTestRun(_currentRun); 205 String[] requirements = _current.getRequirements( 206 _current.getName()); 207 for (int i = 0; i < requirements.length; ++i) { 208 Requirement requirement = _requirements.getRequirement( 209 requirements[i]); 210 if (requirement != null) { 211 current.addRequirementId(requirements[i]); 212 } 213 } 214 result.setCurrentTest(current); 215 } 216 217 HashSet covered = new HashSet(); 218 HashSet requirementIds = new HashSet( 219 _requirements.getRequirements().keySet()); 220 221 // add the requirements covered by the test suite 222 Iterator iter = _coverage.values().iterator(); 223 while (iter.hasNext()) { 224 Coverage coverage = (Coverage) iter.next(); 225 result.addCoverage(coverage); 226 covered.add(coverage.getRequirementId()); 227 } 228 229 // add the list of all requirements not covered by the test suite 230 requirementIds.removeAll(covered); 231 iter = requirementIds.iterator(); 232 while (iter.hasNext()) { 233 String requirementId = (String) iter.next(); 234 Coverage coverage = createCoverage(requirementId); 235 result.addCoverage(coverage); 236 } 237 238 // add the test details 239 iter = _testRuns.values().iterator(); 240 while (iter.hasNext()) { 241 TestRuns runs = (TestRuns) iter.next(); 242 result.addTestRuns(runs); 243 } 244 245 // add failures not associated with any test case 246 iter = _failures.iterator(); 247 while (iter.hasNext()) { 248 result.addFailure((Failure) iter.next()); 249 } 250 return result; 251 } 252 253 /*** 254 * Returns the test state for a particular test, creating it if it 255 * doesn't exist 256 * 257 * @param test the test case 258 * @param context the test context. May be null. 259 * @return the state of the test 260 */ 261 private TestRun getTest(JMSTestCase test, TestContext context) { 262 TestRun result = null; 263 String name = ReportHelper.getName(test); 264 TestRuns testRuns = (TestRuns) _testRuns.get(name); 265 if (testRuns == null) { 266 testRuns = ReportHelper.getTestRuns(test); 267 _testRuns.put(name, testRuns); 268 } else if (context != null) { 269 // see if it exists already 270 Context mapped = ReportHelper.getContext(context); 271 TestRun[] runs = testRuns.getTestRun(); 272 for (int i = 0; i < runs.length; ++i) { 273 if (runs[i].getContext().equals(mapped)) { 274 result = runs[i]; 275 break; 276 } 277 } 278 } 279 if (result == null) { 280 result = ReportHelper.getTestRun(test, context); 281 testRuns.addTestRun(result); 282 } 283 return result; 284 } 285 286 /*** 287 * Add requirement coverage 288 * 289 * @param requirementId the requirement identifier 290 * @param test the test case 291 */ 292 private void addCoverage(String requirementId, JMSTestCase test) { 293 Coverage coverage = getCoverage(requirementId, test); 294 295 if (coverage != null) { 296 String name = ReportHelper.getName(test); 297 String[] tests = coverage.getTest(); 298 boolean found = false; 299 for (int i = 0; i < tests.length; ++i) { 300 if (tests[i].equals(name)) { 301 found = true; 302 break; 303 } 304 } 305 if (!found) { 306 coverage.addTest(name); 307 } 308 int runs = coverage.getRuns(); 309 coverage.setRuns(runs + 1); 310 } 311 } 312 313 /*** 314 * Add a test case failure 315 * 316 * @param test the test case 317 * @param cause the reason for the failure 318 * @param rootCause the root cause of the failure. May be null 319 */ 320 private void addFailure(JMSTestCase test, Throwable cause, 321 Throwable rootCause) { 322 addFailure(test, test.getContext(), cause, rootCause); 323 } 324 325 /*** 326 * Add a test case failure 327 * 328 * @param test the test case 329 * @param context the test context. May be null. 330 * @param cause the reason for the failure 331 * @param rootCause the root cause of the failure. May be null 332 */ 333 private void addFailure(JMSTestCase test, TestContext context, 334 Throwable cause, Throwable rootCause) { 335 TestRun run = getTest(test, context); 336 run.setFailure(ReportHelper.getFailure(cause, rootCause)); 337 338 // get the requirements associated with the test 339 String[] requirements = test.getRequirements(test.getName()); 340 if (requirements == null || requirements.length == 0) { 341 log.error("Test=" + ReportHelper.getName(test) 342 + " is not associated with any requirements"); 343 } else { 344 // increment the failure count against each requirement 345 // associated with the test 346 for (int i = 0; i < requirements.length; ++i) { 347 Coverage coverage = getCoverage(requirements[i], test); 348 if (coverage != null) { 349 int failures = coverage.getFailures(); 350 coverage.setFailures(failures + 1); 351 } 352 } 353 } 354 } 355 356 /*** 357 * Add a failure occuring during setUp/tearDown of a test 358 * 359 * @param runner the test runner 360 * @param cause the reason for the failure 361 * @param rootCause the root cause of the failure. May be null 362 */ 363 private void addFailure(TestRunner runner, Throwable cause, 364 Throwable rootCause) { 365 // locate the test case 366 Test test = runner.getTest(); 367 while (test instanceof TestRunner) { 368 test = ((TestRunner) test).getTest(); 369 } 370 if (test instanceof JMSTestCase) { 371 // log the failure, using the context associated with the runner 372 addFailure((JMSTestCase) test, runner.getContext(), cause, 373 rootCause); 374 } else { 375 // shouldn't happen 376 addFailure(cause, rootCause); 377 } 378 } 379 380 /*** 381 * Add a failure for a test not associated with any requirements 382 * 383 * @param cause the reason for the failure 384 * @param rootCause the root cause of the failure. May be null 385 */ 386 private void addFailure(Throwable cause, Throwable rootCause) { 387 _failures.add(ReportHelper.getFailure(cause, rootCause)); 388 } 389 390 /*** 391 * Returns a coverage instance for the specified requirement identifier. 392 * If none exists, it will be created. 393 * 394 * @param requirementId the requirement identifier 395 * @param test the test case 396 * @return a coverage instance for the specified requirement identifier, 397 * or <code>null</code> if <code>requirementId</code> is invalid 398 */ 399 private Coverage getCoverage(String requirementId, JMSTestCase test) { 400 Coverage coverage = (Coverage) _coverage.get(requirementId); 401 if (coverage == null) { 402 Requirement requirement = _requirements.getRequirement( 403 requirementId); 404 if (requirement != null) { 405 coverage = createCoverage(requirementId); 406 _coverage.put(requirementId, coverage); 407 } else { 408 log.error("Invalid requirement identifier=" 409 + requirementId + " used by test=" 410 + ReportHelper.getName(test)); 411 } 412 } 413 return coverage; 414 } 415 416 /*** 417 * Create a new coverage instance 418 * 419 * @param requirementId the requirement identifier 420 * @return a new coverage instance 421 */ 422 private Coverage createCoverage(String requirementId) { 423 Coverage coverage = new Coverage(); 424 coverage.setRequirementId(requirementId); 425 coverage.setRuns(0); 426 coverage.setFailures(0); 427 return coverage; 428 } 429 430 }

This page was automatically generated by Maven