Clover coverage report - Code Coverage for hivemind release 1.1-beta-1
Coverage timestamp: Thu Apr 28 2005 19:53:41 EDT
file stats: LOC: 595   Methods: 0
NCLOC: 324   Classes: 5
30 day Evaluation Version distributed via the Maven Jar Repository. Clover is not free. You have 30 days to evaluate it. Please visit http://www.thecortex.net/clover to obtain a licensed version of Clover
 
 Source file Conditionals Statements Methods TOTAL
HiveMindTestCase.java - - - -
coverage
 1   
 // Copyright 2004, 2005 The Apache Software Foundation
 2   
 //
 3   
 // Licensed under the Apache License, Version 2.0 (the "License");
 4   
 // you may not use this file except in compliance with the License.
 5   
 // You may obtain a copy of the License at
 6   
 //
 7   
 //     http://www.apache.org/licenses/LICENSE-2.0
 8   
 //
 9   
 // Unless required by applicable law or agreed to in writing, software
 10   
 // distributed under the License is distributed on an "AS IS" BASIS,
 11   
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12   
 // See the License for the specific language governing permissions and
 13   
 // limitations under the License.
 14   
 
 15   
 package org.apache.hivemind.test;
 16   
 
 17   
 import java.net.URL;
 18   
 import java.util.ArrayList;
 19   
 import java.util.Iterator;
 20   
 import java.util.List;
 21   
 import java.util.Locale;
 22   
 
 23   
 import junit.framework.AssertionFailedError;
 24   
 import junit.framework.TestCase;
 25   
 
 26   
 import org.apache.hivemind.ApplicationRuntimeException;
 27   
 import org.apache.hivemind.ClassResolver;
 28   
 import org.apache.hivemind.Location;
 29   
 import org.apache.hivemind.ModuleDescriptorProvider;
 30   
 import org.apache.hivemind.Registry;
 31   
 import org.apache.hivemind.Resource;
 32   
 import org.apache.hivemind.impl.DefaultClassResolver;
 33   
 import org.apache.hivemind.impl.LocationImpl;
 34   
 import org.apache.hivemind.impl.RegistryBuilder;
 35   
 import org.apache.hivemind.impl.XmlModuleDescriptorProvider;
 36   
 import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
 37   
 import org.apache.hivemind.util.ClasspathResource;
 38   
 import org.apache.hivemind.util.PropertyUtils;
 39   
 import org.apache.hivemind.util.URLResource;
 40   
 import org.apache.log4j.Level;
 41   
 import org.apache.log4j.LogManager;
 42   
 import org.apache.log4j.Logger;
 43   
 import org.apache.log4j.spi.LoggingEvent;
 44   
 import org.apache.oro.text.regex.Pattern;
 45   
 import org.apache.oro.text.regex.Perl5Compiler;
 46   
 import org.apache.oro.text.regex.Perl5Matcher;
 47   
 import org.easymock.MockControl;
 48   
 import org.easymock.classextension.MockClassControl;
 49   
 
 50   
 /**
 51   
  * Contains some support for creating HiveMind tests; this is useful enough that has been moved into
 52   
  * the main framework, to simplify creation of tests in the dependent libraries.
 53   
  * 
 54   
  * @author Howard Lewis Ship
 55   
  */
 56   
 public abstract class HiveMindTestCase extends TestCase
 57   
 {
 58   
     ///CLOVER:OFF
 59   
 
 60   
     /**
 61   
      * An instance of {@link DefaultClassResolver} that can be used by tests.
 62   
      */
 63   
 
 64   
     private ClassResolver _classResolver;
 65   
 
 66   
     protected String _interceptedLoggerName;
 67   
 
 68   
     protected StoreAppender _appender;
 69   
 
 70   
     private static Perl5Compiler _compiler;
 71   
 
 72   
     private static Perl5Matcher _matcher;
 73   
 
 74   
     /** List of {@link org.easymock.MockControl}. */
 75   
 
 76   
     private List _controls = new ArrayList();
 77   
 
 78   
     /** @since 1.1 */
 79   
     interface MockControlFactory
 80   
     {
 81   
         public MockControl newControl(Class mockClass);
 82   
     }
 83   
 
 84   
     /** @since 1.1 */
 85   
     private static class InterfaceMockControlFactory implements MockControlFactory
 86   
     {
 87   
         public MockControl newControl(Class mockClass)
 88   
         {
 89   
             return MockControl.createStrictControl(mockClass);
 90   
         }
 91   
     }
 92   
 
 93   
     /** @since 1.1 */
 94   
     private static class ClassMockControlFactory implements MockControlFactory
 95   
     {
 96   
         public MockControl newControl(Class mockClass)
 97   
         {
 98   
             return MockClassControl.createStrictControl(mockClass);
 99   
         }
 100   
     }
 101   
 
 102   
     /** @since 1.1 */
 103   
     static class PlaceholderClassMockControlFactory implements MockControlFactory
 104   
     {
 105   
         public MockControl newControl(Class mockClass)
 106   
         {
 107   
             throw new RuntimeException(
 108   
                     "Unable to instantiate EasyMock control for "
 109   
                             + mockClass
 110   
                             + "; ensure that easymockclassextension-1.1.jar and cglib-full-2.0.1.jar are on the classpath.");
 111   
         }
 112   
     }
 113   
 
 114   
     /** @since 1.1 */
 115   
     private static final MockControlFactory _interfaceMockControlFactory = new InterfaceMockControlFactory();
 116   
 
 117   
     /** @since 1.1 */
 118   
     private static MockControlFactory _classMockControlFactory;
 119   
 
 120   
     static
 121   
     {
 122   
         try
 123   
         {
 124   
             _classMockControlFactory = new ClassMockControlFactory();
 125   
         }
 126   
         catch (NoClassDefFoundError ex)
 127   
         {
 128   
             _classMockControlFactory = new PlaceholderClassMockControlFactory();
 129   
         }
 130   
     }
 131   
 
 132   
     /**
 133   
      * Returns the given file as a {@link Resource}from the classpath. Typically, this is to find
 134   
      * files in the same folder as the invoking class.
 135   
      */
 136   
     protected Resource getResource(String file)
 137   
     {
 138   
         URL url = getClass().getResource(file);
 139   
 
 140   
         if (url == null)
 141   
             throw new NullPointerException("No resource named '" + file + "'.");
 142   
 
 143   
         return new URLResource(url);
 144   
     }
 145   
 
 146   
     /**
 147   
      * Converts the actual list to an array and invokes
 148   
      * {@link #assertListsEqual(Object[], Object[])}.
 149   
      */
 150   
     protected static void assertListsEqual(Object[] expected, List actual)
 151   
     {
 152   
         assertListsEqual(expected, actual.toArray());
 153   
     }
 154   
 
 155   
     /**
 156   
      * Asserts that the two arrays are equal; same length and all elements equal. Checks the
 157   
      * elements first, then the length.
 158   
      */
 159   
     protected static void assertListsEqual(Object[] expected, Object[] actual)
 160   
     {
 161   
         assertNotNull(actual);
 162   
 
 163   
         int min = Math.min(expected.length, actual.length);
 164   
 
 165   
         for (int i = 0; i < min; i++)
 166   
             assertEquals("list[" + i + "]", expected[i], actual[i]);
 167   
 
 168   
         assertEquals("list length", expected.length, actual.length);
 169   
     }
 170   
 
 171   
     /**
 172   
      * Called when code should not be reachable (because a test is expected to throw an exception);
 173   
      * throws AssertionFailedError always.
 174   
      */
 175   
     protected static void unreachable()
 176   
     {
 177   
         throw new AssertionFailedError("This code should be unreachable.");
 178   
     }
 179   
 
 180   
     /**
 181   
      * Sets up an appender to intercept logging for the specified logger. Captured log events can be
 182   
      * recovered via {@link #getInterceptedLogEvents()}.
 183   
      */
 184   
     protected void interceptLogging(String loggerName)
 185   
     {
 186   
         Logger logger = LogManager.getLogger(loggerName);
 187   
 
 188   
         logger.removeAllAppenders();
 189   
 
 190   
         _interceptedLoggerName = loggerName;
 191   
         _appender = new StoreAppender();
 192   
         _appender.activateOptions();
 193   
 
 194   
         logger.setLevel(Level.DEBUG);
 195   
         logger.setAdditivity(false);
 196   
         logger.addAppender(_appender);
 197   
     }
 198   
 
 199   
     /**
 200   
      * Gets the list of events most recently intercepted. This resets the appender, clearing the
 201   
      * list of stored events.
 202   
      * 
 203   
      * @see #interceptLogging(String)
 204   
      */
 205   
 
 206   
     protected List getInterceptedLogEvents()
 207   
     {
 208   
         return _appender.getEvents();
 209   
     }
 210   
 
 211   
     /**
 212   
      * Removes the appender that may have been setup by {@link #interceptLogging(String)}. Also,
 213   
      * invokes {@link org.apache.hivemind.util.PropertyUtils#clearCache()}.
 214   
      */
 215   
     protected void tearDown() throws Exception
 216   
     {
 217   
         super.tearDown();
 218   
 
 219   
         if (_appender != null)
 220   
         {
 221   
             _appender = null;
 222   
 
 223   
             Logger logger = LogManager.getLogger(_interceptedLoggerName);
 224   
             logger.setLevel(null);
 225   
             logger.setAdditivity(true);
 226   
             logger.removeAllAppenders();
 227   
         }
 228   
 
 229   
         PropertyUtils.clearCache();
 230   
 
 231   
         ServiceSerializationHelper.setServiceSerializationSupport(null);
 232   
     }
 233   
 
 234   
     /**
 235   
      * Checks that the provided substring exists in the exceptions message.
 236   
      */
 237   
     protected void assertExceptionSubstring(Throwable ex, String substring)
 238   
     {
 239   
         String message = ex.getMessage();
 240   
         assertNotNull(message);
 241   
 
 242   
         int pos = message.indexOf(substring);
 243   
 
 244   
         if (pos < 0)
 245   
             throw new AssertionFailedError("Exception message (" + message + ") does not contain ["
 246   
                     + substring + "]");
 247   
     }
 248   
 
 249   
     /**
 250   
      * Checks that the message for an exception matches a regular expression.
 251   
      */
 252   
 
 253   
     protected void assertExceptionRegexp(Throwable ex, String pattern) throws Exception
 254   
     {
 255   
         String message = ex.getMessage();
 256   
         assertNotNull(message);
 257   
 
 258   
         setupMatcher();
 259   
 
 260   
         Pattern compiled = _compiler.compile(pattern);
 261   
 
 262   
         if (_matcher.contains(message, compiled))
 263   
             return;
 264   
 
 265   
         throw new AssertionFailedError("Exception message (" + message
 266   
                 + ") does not contain regular expression [" + pattern + "].");
 267   
     }
 268   
 
 269   
     protected void assertRegexp(String pattern, String actual) throws Exception
 270   
     {
 271   
         setupMatcher();
 272   
 
 273   
         Pattern compiled = _compiler.compile(pattern);
 274   
 
 275   
         if (_matcher.contains(actual, compiled))
 276   
             return;
 277   
 
 278   
         throw new AssertionFailedError("\"" + actual + "\" does not contain regular expression["
 279   
                 + pattern + "].");
 280   
     }
 281   
 
 282   
     /**
 283   
      * Digs down through (potentially) a stack of ApplicationRuntimeExceptions until it reaches the
 284   
      * originating exception, which is returned.
 285   
      */
 286   
     protected Throwable findNestedException(ApplicationRuntimeException ex)
 287   
     {
 288   
         Throwable cause = ex.getRootCause();
 289   
 
 290   
         if (cause == null || cause == ex)
 291   
             return ex;
 292   
 
 293   
         if (cause instanceof ApplicationRuntimeException)
 294   
             return findNestedException((ApplicationRuntimeException) cause);
 295   
 
 296   
         return cause;
 297   
     }
 298   
 
 299   
     /**
 300   
      * Checks to see if a specific event matches the name and message.
 301   
      * 
 302   
      * @param message
 303   
      *            exact message to search for
 304   
      * @param events
 305   
      *            the list of events {@link #getInterceptedLogEvents()}
 306   
      * @param index
 307   
      *            the index to check at
 308   
      */
 309   
     private void assertLoggedMessage(String message, List events, int index)
 310   
     {
 311   
         LoggingEvent e = (LoggingEvent) events.get(index);
 312   
 
 313   
         assertEquals("Message", message, e.getMessage());
 314   
     }
 315   
 
 316   
     /**
 317   
      * Checks the messages for all logged events for exact match against the supplied list.
 318   
      */
 319   
     protected void assertLoggedMessages(String[] messages)
 320   
     {
 321   
         List events = getInterceptedLogEvents();
 322   
 
 323   
         for (int i = 0; i < messages.length; i++)
 324   
         {
 325   
             assertLoggedMessage(messages[i], events, i);
 326   
         }
 327   
     }
 328   
 
 329   
     /**
 330   
      * Asserts that some capture log event matches the given message exactly.
 331   
      */
 332   
     protected void assertLoggedMessage(String message)
 333   
     {
 334   
         assertLoggedMessage(message, getInterceptedLogEvents());
 335   
     }
 336   
 
 337   
     /**
 338   
      * Asserts that some capture log event matches the given message exactly.
 339   
      * 
 340   
      * @param message
 341   
      *            to search for; success is finding a logged message contain the parameter as a
 342   
      *            substring
 343   
      * @param events
 344   
      *            from {@link #getInterceptedLogEvents()}
 345   
      */
 346   
     protected void assertLoggedMessage(String message, List events)
 347   
     {
 348   
         int count = events.size();
 349   
 
 350   
         for (int i = 0; i < count; i++)
 351   
         {
 352   
             LoggingEvent e = (LoggingEvent) events.get(i);
 353   
 
 354   
             String eventMessage = String.valueOf(e.getMessage());
 355   
 
 356   
             if (eventMessage.indexOf(message) >= 0)
 357   
                 return;
 358   
         }
 359   
 
 360   
         throw new AssertionFailedError("Could not find logged message: " + message);
 361   
     }
 362   
 
 363   
     protected void assertLoggedMessagePattern(String pattern) throws Exception
 364   
     {
 365   
         assertLoggedMessagePattern(pattern, getInterceptedLogEvents());
 366   
     }
 367   
 
 368   
     protected void assertLoggedMessagePattern(String pattern, List events) throws Exception
 369   
     {
 370   
         setupMatcher();
 371   
 
 372   
         Pattern compiled = null;
 373   
 
 374   
         int count = events.size();
 375   
 
 376   
         for (int i = 0; i < count; i++)
 377   
         {
 378   
             LoggingEvent e = (LoggingEvent) events.get(i);
 379   
 
 380   
             String eventMessage = e.getMessage().toString();
 381   
 
 382   
             if (compiled == null)
 383   
                 compiled = _compiler.compile(pattern);
 384   
 
 385   
             if (_matcher.contains(eventMessage, compiled))
 386   
                 return;
 387   
 
 388   
         }
 389   
 
 390   
         throw new AssertionFailedError("Could not find logged message with pattern: " + pattern);
 391   
     }
 392   
 
 393   
     private void setupMatcher()
 394   
     {
 395   
         if (_compiler == null)
 396   
             _compiler = new Perl5Compiler();
 397   
 
 398   
         if (_matcher == null)
 399   
             _matcher = new Perl5Matcher();
 400   
     }
 401   
 
 402   
     /**
 403   
      * Convienience method for invoking {@link #buildFrameworkRegistry(String[])}with only a single
 404   
      * file.
 405   
      */
 406   
     protected Registry buildFrameworkRegistry(String file) throws Exception
 407   
     {
 408   
         return buildFrameworkRegistry(new String[]
 409   
         { file });
 410   
     }
 411   
 
 412   
     /**
 413   
      * Builds a minimal registry, containing only the specified files, plus the master module
 414   
      * descriptor (i.e., those visible on the classpath). Files are resolved using
 415   
      * {@link HiveMindTestCase#getResource(String)}.
 416   
      */
 417   
     protected Registry buildFrameworkRegistry(String[] files) throws Exception
 418   
     {
 419   
         ClassResolver resolver = getClassResolver();
 420   
 
 421   
         List descriptorResources = new ArrayList();
 422   
         for (int i = 0; i < files.length; i++)
 423   
         {
 424   
             Resource resource = getResource(files[i]);
 425   
 
 426   
             descriptorResources.add(resource);
 427   
         }
 428   
 
 429   
         ModuleDescriptorProvider provider = new XmlModuleDescriptorProvider(resolver,
 430   
                 descriptorResources);
 431   
 
 432   
         return buildFrameworkRegistry(provider);
 433   
     }
 434   
 
 435   
     /**
 436   
      * Builds a registry, containing only the modules delivered by the specified
 437   
      * {@link org.apache.hivemind.ModuleDescriptorProvider}, plus the master module descriptor
 438   
      * (i.e., those visible on the classpath).
 439   
      */
 440   
     protected Registry buildFrameworkRegistry(ModuleDescriptorProvider customProvider)
 441   
     {
 442   
         ClassResolver resolver = getClassResolver();
 443   
 
 444   
         RegistryBuilder builder = new RegistryBuilder();
 445   
 
 446   
         builder.addModuleDescriptorProvider(new XmlModuleDescriptorProvider(resolver));
 447   
         builder.addModuleDescriptorProvider(customProvider);
 448   
 
 449   
         return builder.constructRegistry(Locale.getDefault());
 450   
     }
 451   
 
 452   
     /**
 453   
      * Builds a registry from exactly the provided resource; this registry will not include the
 454   
      * <code>hivemind</code> module.
 455   
      */
 456   
     protected Registry buildMinimalRegistry(Resource l) throws Exception
 457   
     {
 458   
         RegistryBuilder builder = new RegistryBuilder();
 459   
 
 460   
         return builder.constructRegistry(Locale.getDefault());
 461   
     }
 462   
 
 463   
     /**
 464   
      * Creates a <em>managed</em> control via
 465   
      * {@link MockControl#createStrictControl(java.lang.Class)}. The created control is remembered,
 466   
      * and will be invoked by {@link #replayControls()},{@link #verifyControls()}, etc..
 467   
      * <p>
 468   
      * The class to mock may be either an interface or a class. The EasyMock class extension
 469   
      * (easymockclassextension-1.1.jar) and CGLIB (cglib-full-2.01.jar) must be present in the
 470   
      * latter case (new since 1.1).
 471   
      */
 472   
     protected MockControl newControl(Class mockClass)
 473   
     {
 474   
         MockControlFactory factory = mockClass.isInterface() ? _interfaceMockControlFactory
 475   
                 : _classMockControlFactory;
 476   
 
 477   
         MockControl result = factory.newControl(mockClass);
 478   
 
 479   
         addControl(result);
 480   
 
 481   
         return result;
 482   
     }
 483   
 
 484   
     /**
 485   
      * Adds the control to the list of managed controls used by {@link #replayControls()}and
 486   
      * {@link #verifyControls()}.
 487   
      */
 488   
     protected void addControl(MockControl control)
 489   
     {
 490   
         _controls.add(control);
 491   
     }
 492   
 
 493   
     /**
 494   
      * Convienience for invoking {@link #newControl(Class)}and then invoking
 495   
      * {@link MockControl#getMock()}on the result.
 496   
      */
 497   
     protected Object newMock(Class mockClass)
 498   
     {
 499   
         return newControl(mockClass).getMock();
 500   
     }
 501   
 
 502   
     /**
 503   
      * Invokes {@link MockControl#replay()}on all controls created by {@link #newControl(Class)}.
 504   
      */
 505   
     protected void replayControls()
 506   
     {
 507   
         Iterator i = _controls.iterator();
 508   
         while (i.hasNext())
 509   
         {
 510   
             MockControl c = (MockControl) i.next();
 511   
             c.replay();
 512   
         }
 513   
     }
 514   
 
 515   
     /**
 516   
      * Invokes {@link org.easymock.MockControl#verify()}and {@link MockControl#reset()}on all
 517   
      * controls created by {@link #newControl(Class)}.
 518   
      */
 519   
 
 520   
     protected void verifyControls()
 521   
     {
 522   
         Iterator i = _controls.iterator();
 523   
         while (i.hasNext())
 524   
         {
 525   
             MockControl c = (MockControl) i.next();
 526   
             c.verify();
 527   
             c.reset();
 528   
         }
 529   
     }
 530   
 
 531   
     /**
 532   
      * Invokes {@link org.easymock.MockControl#reset()}on all controls.
 533   
      */
 534   
 
 535   
     protected void resetControls()
 536   
     {
 537   
         Iterator i = _controls.iterator();
 538   
         while (i.hasNext())
 539   
         {
 540   
             MockControl c = (MockControl) i.next();
 541   
             c.reset();
 542   
         }
 543   
     }
 544   
 
 545   
     /**
 546   
      * @deprecated To be removed in 1.2. Use XXX instead.
 547   
      */
 548   
     protected Location fabricateLocation(int line)
 549   
     {
 550   
         String path = "/" + getClass().getName().replace('.', '/');
 551   
 
 552   
         Resource r = new ClasspathResource(getClassResolver(), path);
 553   
 
 554   
         return new LocationImpl(r, line);
 555   
     }
 556   
 
 557   
     private int _line = 1;
 558   
 
 559   
     /**
 560   
      * Returns a new {@link Location}&nbsp;instance. The resource is the test class, and the line
 561   
      * number increments by one from one for each invocation (thus each call will get a unique
 562   
      * instance not equal to any previously obtained instance).
 563   
      * 
 564   
      * @since 1.1
 565   
      */
 566   
     protected Location newLocation()
 567   
     {
 568   
         return fabricateLocation(_line++);
 569   
     }
 570   
 
 571   
     /**
 572   
      * Returns a {@link DefaultClassResolver}. Repeated calls in the same test return the same
 573   
      * value.
 574   
      * 
 575   
      * @since 1.1
 576   
      */
 577   
 
 578   
     protected ClassResolver getClassResolver()
 579   
     {
 580   
         if (_classResolver == null)
 581   
             _classResolver = new DefaultClassResolver();
 582   
 
 583   
         return _classResolver;
 584   
     }
 585   
 
 586   
     protected boolean matches(String input, String pattern) throws Exception
 587   
     {
 588   
         setupMatcher();
 589   
 
 590   
         Pattern compiled = _compiler.compile(pattern);
 591   
 
 592   
         return _matcher.matches(input, compiled);
 593   
     }
 594   
 
 595   
 }