KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > hivemind > test > HiveMindTestCase


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 JavaDoc;
18 import java.util.ArrayList JavaDoc;
19 import java.util.Iterator JavaDoc;
20 import java.util.List JavaDoc;
21 import java.util.Locale JavaDoc;
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.Registry;
30 import org.apache.hivemind.Resource;
31 import org.apache.hivemind.definition.ModuleDefinition;
32 import org.apache.hivemind.definition.RegistryDefinition;
33 import org.apache.hivemind.definition.impl.RegistryDefinitionImpl;
34 import org.apache.hivemind.impl.DefaultClassResolver;
35 import org.apache.hivemind.impl.LocationImpl;
36 import org.apache.hivemind.impl.RegistryBuilder;
37 import org.apache.hivemind.internal.ser.ServiceSerializationHelper;
38 import org.apache.hivemind.util.ClasspathResource;
39 import org.apache.hivemind.util.PropertyUtils;
40 import org.apache.hivemind.util.URLResource;
41 import org.apache.log4j.Level;
42 import org.apache.log4j.LogManager;
43 import org.apache.log4j.Logger;
44 import org.apache.log4j.spi.LoggingEvent;
45 import org.apache.oro.text.regex.Pattern;
46 import org.apache.oro.text.regex.Perl5Compiler;
47 import org.apache.oro.text.regex.Perl5Matcher;
48 import org.easymock.MockControl;
49 import org.easymock.classextension.MockClassControl;
50
51 /**
52  * Contains some support for creating HiveMind tests; this is useful enough that has been moved into
53  * the main framework, to simplify creation of tests in the dependent libraries.
54  *
55  * @author Howard Lewis Ship
56  */

57 public abstract class HiveMindTestCase extends TestCase
58 {
59     // /CLOVER:OFF
60

61     /**
62      * An instance of {@link DefaultClassResolver} that can be used by tests.
63      */

64
65     private ClassResolver _classResolver;
66
67     protected String JavaDoc _interceptedLoggerName;
68
69     protected StoreAppender _appender;
70
71     private static Perl5Compiler _compiler;
72
73     private static Perl5Matcher _matcher;
74
75     /** List of {@link org.easymock.MockControl}. */
76
77     private List JavaDoc _controls = new ArrayList JavaDoc();
78
79     /** @since 1.1 */
80     interface MockControlFactory
81     {
82         public MockControl newControl(Class JavaDoc mockClass);
83     }
84
85     /** @since 1.1 */
86     private static class InterfaceMockControlFactory implements MockControlFactory
87     {
88         public MockControl newControl(Class JavaDoc mockClass)
89         {
90             return MockControl.createStrictControl(mockClass);
91         }
92     }
93
94     /** @since 1.1 */
95     private static class ClassMockControlFactory implements MockControlFactory
96     {
97         public MockControl newControl(Class JavaDoc mockClass)
98         {
99             return MockClassControl.createStrictControl(mockClass);
100         }
101     }
102
103     /** @since 1.1 */
104     static class PlaceholderClassMockControlFactory implements MockControlFactory
105     {
106         public MockControl newControl(Class JavaDoc mockClass)
107         {
108             throw new RuntimeException JavaDoc(
109                     "Unable to instantiate EasyMock control for "
110                             + mockClass
111                             + "; ensure that easymockclassextension-1.1.jar and cglib-full-2.0.1.jar are on the classpath.");
112         }
113     }
114
115     /** @since 1.1 */
116     private static final MockControlFactory _interfaceMockControlFactory = new InterfaceMockControlFactory();
117
118     /** @since 1.1 */
119     private static MockControlFactory _classMockControlFactory;
120
121     static
122     {
123         try
124         {
125             _classMockControlFactory = new ClassMockControlFactory();
126         }
127         catch (NoClassDefFoundError JavaDoc ex)
128         {
129             _classMockControlFactory = new PlaceholderClassMockControlFactory();
130         }
131     }
132
133     /**
134      * Returns the given file as a {@link Resource} from the classpath. Typically, this is to find
135      * files in the same folder as the invoking class.
136      */

137     protected Resource getResource(String JavaDoc file)
138     {
139         URL JavaDoc url = getClass().getResource(file);
140
141         if (url == null)
142             throw new NullPointerException JavaDoc("No resource named '" + file + "'.");
143
144         return new URLResource(url);
145     }
146
147     /**
148      * Converts the actual list to an array and invokes
149      * {@link #assertListsEqual(Object[], Object[])}.
150      */

151     protected static void assertListsEqual(Object JavaDoc[] expected, List JavaDoc actual)
152     {
153         assertListsEqual(expected, actual.toArray());
154     }
155
156     /**
157      * Asserts that the two arrays are equal; same length and all elements equal. Checks the
158      * elements first, then the length.
159      */

160     protected static void assertListsEqual(Object JavaDoc[] expected, Object JavaDoc[] actual)
161     {
162         assertNotNull(actual);
163
164         int min = Math.min(expected.length, actual.length);
165
166         for (int i = 0; i < min; i++)
167             assertEquals("list[" + i + "]", expected[i], actual[i]);
168
169         assertEquals("list length", expected.length, actual.length);
170     }
171
172     /**
173      * Called when code should not be reachable (because a test is expected to throw an exception);
174      * throws AssertionFailedError always.
175      */

176     protected static void unreachable()
177     {
178         throw new AssertionFailedError("This code should be unreachable.");
179     }
180
181     /**
182      * Sets up an appender to intercept logging for the specified logger. Captured log events can be
183      * recovered via {@link #getInterceptedLogEvents()}.
184      */

185     protected void interceptLogging(String JavaDoc loggerName)
186     {
187         Logger logger = LogManager.getLogger(loggerName);
188
189         logger.removeAllAppenders();
190
191         _interceptedLoggerName = loggerName;
192         _appender = new StoreAppender();
193         _appender.activateOptions();
194
195         logger.setLevel(Level.DEBUG);
196         logger.setAdditivity(false);
197         logger.addAppender(_appender);
198     }
199
200     /**
201      * Gets the list of events most recently intercepted. This resets the appender, clearing the
202      * list of stored events.
203      *
204      * @see #interceptLogging(String)
205      */

206
207     protected List JavaDoc getInterceptedLogEvents()
208     {
209         return _appender.getEvents();
210     }
211
212     /**
213      * Removes the appender that may have been setup by {@link #interceptLogging(String)}. Also,
214      * invokes {@link org.apache.hivemind.util.PropertyUtils#clearCache()}.
215      */

216     protected void tearDown() throws Exception JavaDoc
217     {
218         super.tearDown();
219
220         if (_appender != null)
221         {
222             _appender = null;
223
224             Logger logger = LogManager.getLogger(_interceptedLoggerName);
225             logger.setLevel(null);
226             logger.setAdditivity(true);
227             logger.removeAllAppenders();
228         }
229
230         PropertyUtils.clearCache();
231
232         ServiceSerializationHelper.setServiceSerializationSupport(null);
233     }
234
235     /**
236      * Checks that the provided substring exists in the exceptions message.
237      */

238     protected void assertExceptionSubstring(Throwable JavaDoc ex, String JavaDoc substring)
239     {
240         String JavaDoc message = ex.getMessage();
241         assertNotNull(message);
242
243         int pos = message.indexOf(substring);
244
245         if (pos < 0)
246             throw new AssertionFailedError("Exception message (" + message + ") does not contain ["
247                     + substring + "]");
248     }
249
250     /**
251      * Checks that the message for an exception matches a regular expression.
252      */

253
254     protected void assertExceptionRegexp(Throwable JavaDoc ex, String JavaDoc pattern) throws Exception JavaDoc
255     {
256         String JavaDoc message = ex.getMessage();
257         assertNotNull(message);
258
259         setupMatcher();
260
261         Pattern compiled = _compiler.compile(pattern);
262
263         if (_matcher.contains(message, compiled))
264             return;
265
266         throw new AssertionFailedError("Exception message (" + message
267                 + ") does not contain regular expression [" + pattern + "].");
268     }
269
270     protected void assertRegexp(String JavaDoc pattern, String JavaDoc actual) throws Exception JavaDoc
271     {
272         setupMatcher();
273
274         Pattern compiled = _compiler.compile(pattern);
275
276         if (_matcher.contains(actual, compiled))
277             return;
278
279         throw new AssertionFailedError("\"" + actual + "\" does not contain regular expression["
280                 + pattern + "].");
281     }
282
283     /**
284      * Digs down through (potentially) a stack of ApplicationRuntimeExceptions until it reaches the
285      * originating exception, which is returned.
286      */

287     protected Throwable JavaDoc findNestedException(ApplicationRuntimeException ex)
288     {
289         Throwable JavaDoc cause = ex.getRootCause();
290
291         if (cause == null || cause == ex)
292             return ex;
293
294         if (cause instanceof ApplicationRuntimeException)
295             return findNestedException((ApplicationRuntimeException) cause);
296
297         return cause;
298     }
299
300     /**
301      * Checks to see if a specific event matches the name and message.
302      *
303      * @param message
304      * exact message to search for
305      * @param events
306      * the list of events {@link #getInterceptedLogEvents()}
307      * @param index
308      * the index to check at
309      */

310     private void assertLoggedMessage(String JavaDoc message, List JavaDoc events, int index)
311     {
312         LoggingEvent e = (LoggingEvent) events.get(index);
313
314         assertEquals("Message", message, e.getMessage());
315     }
316
317     /**
318      * Checks the messages for all logged events for exact match against the supplied list.
319      */

320     protected void assertLoggedMessages(String JavaDoc[] messages)
321     {
322         List JavaDoc events = getInterceptedLogEvents();
323
324         for (int i = 0; i < messages.length; i++)
325         {
326             assertLoggedMessage(messages[i], events, i);
327         }
328     }
329
330     /**
331      * Asserts that some capture log event matches the given message exactly.
332      */

333     protected void assertLoggedMessage(String JavaDoc message)
334     {
335         assertLoggedMessage(message, getInterceptedLogEvents());
336     }
337
338     /**
339      * Asserts that some capture log event matches the given message exactly.
340      *
341      * @param message
342      * to search for; success is finding a logged message contain the parameter as a
343      * substring
344      * @param events
345      * from {@link #getInterceptedLogEvents()}
346      */

347     protected void assertLoggedMessage(String JavaDoc message, List JavaDoc events)
348     {
349         int count = events.size();
350
351         for (int i = 0; i < count; i++)
352         {
353             LoggingEvent e = (LoggingEvent) events.get(i);
354
355             String JavaDoc eventMessage = String.valueOf(e.getMessage());
356
357             if (eventMessage.indexOf(message) >= 0)
358                 return;
359         }
360
361         throw new AssertionFailedError("Could not find logged message: " + message);
362     }
363
364     protected void assertLoggedMessagePattern(String JavaDoc pattern) throws Exception JavaDoc
365     {
366         assertLoggedMessagePattern(pattern, getInterceptedLogEvents());
367     }
368
369     protected void assertLoggedMessagePattern(String JavaDoc pattern, List JavaDoc events) throws Exception JavaDoc
370     {
371         setupMatcher();
372
373         Pattern compiled = null;
374
375         int count = events.size();
376
377         for (int i = 0; i < count; i++)
378         {
379             LoggingEvent e = (LoggingEvent) events.get(i);
380
381             String JavaDoc eventMessage = e.getMessage().toString();
382
383             if (compiled == null)
384                 compiled = _compiler.compile(pattern);
385
386             if (_matcher.contains(eventMessage, compiled))
387                 return;
388
389         }
390
391         throw new AssertionFailedError("Could not find logged message with pattern: " + pattern);
392     }
393
394     private void setupMatcher()
395     {
396         if (_compiler == null)
397             _compiler = new Perl5Compiler();
398
399         if (_matcher == null)
400             _matcher = new Perl5Matcher();
401     }
402
403     protected Registry buildFrameworkRegistry(ModuleDefinition customModule)
404     {
405         return buildFrameworkRegistry(new ModuleDefinition[] {customModule});
406     }
407
408     /**
409      * Builds a registry, containing only the modules delivered the parameter
410      * <code>customModules</code>, plus the master module descriptor
411      * (i.e., those visible on the classpath).
412      */

413     protected Registry buildFrameworkRegistry(ModuleDefinition[] customModules)
414     {
415         RegistryDefinition registryDefinition = new RegistryDefinitionImpl();
416         for (int i = 0; i < customModules.length; i++)
417         {
418             ModuleDefinition module = customModules[i];
419             registryDefinition.addModule(module);
420         }
421
422         RegistryBuilder builder = new RegistryBuilder(registryDefinition);
423         return builder.constructRegistry(Locale.getDefault());
424     }
425
426     /**
427      * Builds a registry from exactly the provided resource; this registry will not include the
428      * <code>hivemind</code> module.
429      */

430     protected Registry buildMinimalRegistry(Resource l) throws Exception JavaDoc
431     {
432         RegistryBuilder builder = new RegistryBuilder();
433
434         return builder.constructRegistry(Locale.getDefault());
435     }
436
437     /**
438      * Creates a <em>managed</em> control via
439      * {@link MockControl#createStrictControl(java.lang.Class)}. The created control is remembered,
440      * and will be invoked by {@link #replayControls()}, {@link #verifyControls()}, etc.
441      * <p>
442      * The class to mock may be either an interface or a class. The EasyMock class extension
443      * (easymockclassextension-1.1.jar) and CGLIB (cglib-full-2.01.jar) must be present in the
444      * latter case (new since 1.1).
445      * <p>
446      * This method is not deprecated, but is rarely used; typically {@link #newMock(Class)} is used
447      * to create the control and the mock, and {@link #setReturnValue(Object, Object)} and
448      * {@link #setThrowable(Object, Throwable)} are used to while training it.
449      * {@link #getControl(Object)} is used for the rare cases where the MockControl itself is
450      * needed.
451      */

452     protected MockControl newControl(Class JavaDoc mockClass)
453     {
454         MockControlFactory factory = mockClass.isInterface() ? _interfaceMockControlFactory
455                 : _classMockControlFactory;
456
457         MockControl result = factory.newControl(mockClass);
458
459         addControl(result);
460
461         return result;
462     }
463
464     /**
465      * Accesses the control for a previously created mock object. Iterates over the list of managed
466      * controls until one is found whose mock object identity equals the mock object provided.
467      *
468      * @param mock
469      * object whose control is needed
470      * @return the corresponding MockControl if found
471      * @throws IllegalArgumentException
472      * if not found
473      * @since 1.1
474      */

475
476     protected MockControl getControl(Object JavaDoc mock)
477     {
478         Iterator JavaDoc i = _controls.iterator();
479         while (i.hasNext())
480         {
481             MockControl control = (MockControl) i.next();
482
483             if (control.getMock() == mock)
484                 return control;
485         }
486
487         throw new IllegalArgumentException JavaDoc(mock
488                 + " is not a mock object controlled by any registered MockControl instance.");
489     }
490
491     /**
492      * Invoked when training a mock object to set the Throwable for the most recently invoked
493      * method.
494      *
495      * @param mock
496      * the mock object being trained
497      * @param t
498      * the exception the object should throw when it replays
499      * @since 1.1
500      */

501     protected void setThrowable(Object JavaDoc mock, Throwable JavaDoc t)
502     {
503         getControl(mock).setThrowable(t);
504     }
505
506     /**
507      * Invoked when training a mock object to set the return value for the most recently invoked
508      * method. Overrides of this method exist to support a number of primitive types.
509      *
510      * @param mock
511      * the mock object being trained
512      * @param returnValue
513      * the value to return from the most recently invoked methods
514      * @since 1.1
515      */

516     protected void setReturnValue(Object JavaDoc mock, Object JavaDoc returnValue)
517     {
518         getControl(mock).setReturnValue(returnValue);
519     }
520
521     /**
522      * Invoked when training a mock object to set the return value for the most recently invoked
523      * method. Overrides of this method exist to support a number of primitive types.
524      *
525      * @param mock
526      * the mock object being trained
527      * @param returnValue
528      * the value to return from the most recently invoked methods
529      * @since 1.1
530      */

531     protected void setReturnValue(Object JavaDoc mock, long returnValue)
532     {
533         getControl(mock).setReturnValue(returnValue);
534     }
535
536     /**
537      * Invoked when training a mock object to set the return value for the most recently invoked
538      * method. Overrides of this method exist to support a number of primitive types.
539      *
540      * @param mock
541      * the mock object being trained
542      * @param returnValue
543      * the value to return from the most recently invoked methods
544      * @since 1.1
545      */

546     protected void setReturnValue(Object JavaDoc mock, float returnValue)
547     {
548         getControl(mock).setReturnValue(returnValue);
549     }
550
551     /**
552      * Invoked when training a mock object to set the return value for the most recently invoked
553      * method. Overrides of this method exist to support a number of primitive types.
554      *
555      * @param mock
556      * the mock object being trained
557      * @param returnValue
558      * the value to return from the most recently invoked methods
559      * @since 1.1
560      */

561     protected void setReturnValue(Object JavaDoc mock, double returnValue)
562     {
563         getControl(mock).setReturnValue(returnValue);
564     }
565
566     /**
567      * Invoked when training a mock object to set the return value for the most recently invoked
568      * method. Overrides of this method exist to support a number of primitive types.
569      *
570      * @param mock
571      * the mock object being trained
572      * @param returnValue
573      * the value to return from the most recently invoked methods
574      * @since 1.1
575      */

576     protected void setReturnValue(Object JavaDoc mock, boolean returnValue)
577     {
578         getControl(mock).setReturnValue(returnValue);
579     }
580
581     /**
582      * Adds the control to the list of managed controls used by {@link #replayControls()} and
583      * {@link #verifyControls()}.
584      */

585     protected void addControl(MockControl control)
586     {
587         _controls.add(control);
588     }
589
590     /**
591      * Convienience for invoking {@link #newControl(Class)} and then invoking
592      * {@link MockControl#getMock()} on the result.
593      */

594     protected Object JavaDoc newMock(Class JavaDoc mockClass)
595     {
596         return newControl(mockClass).getMock();
597     }
598
599     /**
600      * Invokes {@link MockControl#replay()} on all controls created by {@link #newControl(Class)}.
601      */

602     protected void replayControls()
603     {
604         Iterator JavaDoc i = _controls.iterator();
605         while (i.hasNext())
606         {
607             MockControl c = (MockControl) i.next();
608             c.replay();
609         }
610     }
611
612     /**
613      * Invokes {@link org.easymock.MockControl#verify()} and {@link MockControl#reset()} on all
614      * controls created by {@link #newControl(Class)}.
615      */

616
617     protected void verifyControls()
618     {
619         Iterator JavaDoc i = _controls.iterator();
620         while (i.hasNext())
621         {
622             MockControl c = (MockControl) i.next();
623             c.verify();
624             c.reset();
625         }
626     }
627
628     /**
629      * Invokes {@link org.easymock.MockControl#reset()} on all controls.
630      */

631
632     protected void resetControls()
633     {
634         Iterator JavaDoc i = _controls.iterator();
635         while (i.hasNext())
636         {
637             MockControl c = (MockControl) i.next();
638             c.reset();
639         }
640     }
641
642     /**
643      * @deprecated To be removed in 1.2. Use {@link #newLocation()} instead.
644      */

645     protected Location fabricateLocation(int line)
646     {
647         String JavaDoc path = "/" + getClass().getName().replace('.', '/');
648
649         Resource r = new ClasspathResource(getClassResolver(), path);
650
651         return new LocationImpl(r, line);
652     }
653
654     private int _line = 1;
655
656     /**
657      * Returns a new {@link Location} instance. The resource is the test class, and the line number
658      * increments by one from one for each invocation (thus each call will get a unique instance not
659      * equal to any previously obtained instance).
660      *
661      * @since 1.1
662      */

663     protected Location newLocation()
664     {
665         return fabricateLocation(_line++);
666     }
667
668     /**
669      * Returns a {@link DefaultClassResolver}. Repeated calls in the same test return the same
670      * value.
671      *
672      * @since 1.1
673      */

674
675     protected ClassResolver getClassResolver()
676     {
677         if (_classResolver == null)
678             _classResolver = new DefaultClassResolver();
679
680         return _classResolver;
681     }
682
683     protected boolean matches(String JavaDoc input, String JavaDoc pattern) throws Exception JavaDoc
684     {
685         setupMatcher();
686
687         Pattern compiled = _compiler.compile(pattern);
688
689         return _matcher.matches(input, compiled);
690     }
691
692 }
Popular Tags