SUPER! :) http://people.apache.org/~simonetripodi/ http://simonetripodi.livejournal.com/ http://twitter.com/simonetripodi http://www.99soft.org/
On Mon, Mar 11, 2013 at 4:12 PM, <e...@apache.org> wrote: > Author: eric > Date: Mon Mar 11 15:12:05 2013 > New Revision: 1455170 > > URL: http://svn.apache.org/r1455170 > Log: > [ONAMI-101] Add support for OnamiSuite > > Added: > > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java > > incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java > Modified: > > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java > > Modified: > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java > URL: > http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java?rev=1455170&r1=1455169&r2=1455170&view=diff > ============================================================================== > --- > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java > (original) > +++ > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiRunner.java > Mon Mar 11 15:12:05 2013 > @@ -46,6 +46,7 @@ import org.apache.onami.test.reflection. > import org.apache.onami.test.reflection.HandleException; > import org.junit.runner.notification.RunNotifier; > import org.junit.runners.BlockJUnit4ClassRunner; > +import org.junit.runners.Suite; > import org.junit.runners.model.FrameworkMethod; > import org.junit.runners.model.InitializationError; > > @@ -170,6 +171,42 @@ public class OnamiRunner > } > > /** > + * OnamiRunner constructor to create the runner needed > + * by the OnamiSuite class. > + * > + * @see org.junit.runner.RunWith > + * @param suite The suite test case class to run. > + * @param test The test case class to run. > + * @throws org.junit.runners.model.InitializationError if any error > occurs. > + */ > + public OnamiRunner( Class<?> suite, Class<?> test ) > + throws InitializationError > + { > + super( test ); > + > + try > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( "Inizializing injector for test class: " + > test.getName() ); > + } > + > + this.allModules = inizializeInjector( suite, test ); > + > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( "done..." ); > + } > + } > + catch ( Exception e ) > + { > + final List<Throwable> throwables = new LinkedList<Throwable>(); > + throwables.add( e ); > + throw new InitializationError( throwables ); > + } > + } > + > + /** > * {@inheritDoc} > */ > public void run( final RunNotifier notifier ) > @@ -222,6 +259,7 @@ public class OnamiRunner > * @return The instance of the test case. > * @throws Exception when an error occurs. > */ > + @Override > protected Object createTest() > throws Exception > { > @@ -244,6 +282,30 @@ public class OnamiRunner > } > > /** > + * This method collects modules from {@link GuiceModules}, {@link > GuiceProvidedModules}, {@link Mock} > + * and {@ OnamiSuite}. > + * > + * @param <T> whatever input type is accepted > + * @param suite the input suite to be analyzed > + * @param test the input class has to be analyzed > + * @return a List of Guice Modules built after input class analysis. > + * @throws IllegalAccessException when a n error occurs. > + * @throws InstantiationException when a n error occurs. > + * @throws HandleException when a n error occurs. > + */ > + protected <T> List<Module> inizializeInjector( Class<?> suite, Class<T> > test) > + throws HandleException, InstantiationException, > IllegalAccessException > + { > + final List<Module> modules = inizializeInjector(test); > + Module m = visitClass( suite ); > + if ( m != null ) > + { > + modules.add( m ); > + } > + return modules; > + } > + > + /** > * This method collects modules from {@link GuiceModules}, {@link > GuiceProvidedModules}, {@link Mock}. > * > * @param <T> whatever input type is accepted > > Added: > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java > URL: > http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java?rev=1455170&view=auto > ============================================================================== > --- > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java > (added) > +++ > incubator/onami/trunk/test/src/main/java/org/apache/onami/test/OnamiSuite.java > Mon Mar 11 15:12:05 2013 > @@ -0,0 +1,452 @@ > +package org.apache.onami.test; > + > +/* > + * Licensed to the Apache Software Foundation (ASF) under one > + * or more contributor license agreements. See the NOTICE file > + * distributed with this work for additional information > + * regarding copyright ownership. The ASF licenses this file > + * to you under the Apache License, Version 2.0 (the > + * "License"); you may not use this file except in compliance > + * with the License. You may obtain a copy of the License at > + * > + * http://www.apache.org/licenses/LICENSE-2.0 > + * > + * Unless required by applicable law or agreed to in writing, > + * software distributed under the License is distributed on an > + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY > + * KIND, either express or implied. See the License for the > + * specific language governing permissions and limitations > + * under the License. > + */ > + > +import java.lang.reflect.Field; > +import java.lang.reflect.Modifier; > +import java.util.ArrayList; > +import java.util.HashMap; > +import java.util.LinkedList; > +import java.util.List; > +import java.util.Map; > +import java.util.Map.Entry; > +import java.util.logging.Level; > +import java.util.logging.Logger; > + > +import org.apache.onami.test.annotation.GuiceModules; > +import org.apache.onami.test.annotation.GuiceProvidedModules; > +import org.apache.onami.test.annotation.Mock; > +import org.apache.onami.test.annotation.MockFramework; > +import org.apache.onami.test.annotation.MockType; > +import org.apache.onami.test.handler.GuiceInjectableClassHandler; > +import org.apache.onami.test.handler.GuiceModuleHandler; > +import org.apache.onami.test.handler.GuiceProvidedModuleHandler; > +import org.apache.onami.test.handler.MockFrameworkHandler; > +import org.apache.onami.test.handler.MockHandler; > +import org.apache.onami.test.mock.MockEngine; > +import org.apache.onami.test.mock.guice.MockTypeListener; > +import org.apache.onami.test.reflection.ClassVisitor; > +import org.apache.onami.test.reflection.HandleException; > +import org.junit.runner.Runner; > +import org.junit.runner.notification.RunNotifier; > +import org.junit.runners.Suite; > +import org.junit.runners.model.InitializationError; > +import org.junit.runners.model.RunnerBuilder; > + > +import com.google.inject.AbstractModule; > +import com.google.inject.Guice; > +import com.google.inject.Inject; > +import com.google.inject.Injector; > +import com.google.inject.Module; > +import com.google.inject.matcher.Matchers; > +import com.google.inject.util.Modules; > + > +/** > + * <p> > + * It's a {@link Suite} runner. > + * </p> > + * <p> > + * This class creates a Google Guice {@link Injector} configured by {@link > GuiceModules} annotation (only fr modules > + * with default constructor) and {@link GuiceProvidedModules} annotation and > {@link Mock}. > + * </p> > + * <p> > + * <b>Example #1:</b> <br> > + * > + * <pre> > + * > + * @org.junit.runner.RunWith( OnamiSuite.class ) > + * @GuiceModules( SimpleModule.class ) > + * @SuiteClasses({ .class }) > + * public class AcmeTestCase > + * { > + * > + * @GuiceProvidedModules > + * static public Module getProperties() > + * { > + * ... > + * return Modules.combine(new ComplexModule( loadProperies() ), ... > ); > + * } > + * > + * </pre> > + * > + * </p> > + * <p> > + * <b>Example #2:</b> <br> > + * > + * <pre> > + * > + * @org.junit.runner.RunWith( OnamiSuite.class ) > + * public class AcmeTestCase > + * extends com.google.inject.AbstractModule > + * { > + * > + * public void configure() > + * { > + * // Configure your proper modules > + * ... > + * bind( Service.class ).annotatedWith( TestAnnotation.class ).to( > ServiceTestImpl.class ); > + * ... > + * } > + * > + * @Mock > + * private AnotherService serviceMock; > + * > + * @Inject > + * private Service serviceTest; > + * > + * @org.junit.Test > + * public void test() > + * { > + * assertNotNull( serviceMock ); > + * assertNotNull( serviceTest ); > + * } > + * </pre> > + * > + * </p> > + * > + * @see GuiceMockModule > + */ > +public class OnamiSuite > + extends Suite > +{ > + > + private static final Logger LOGGER = Logger.getLogger( > OnamiSuite.class.getName() ); > + > + private Injector injector; > + > + private final List<Module> allModules; > + > + private final Map<Field, Object> mocked = new HashMap<Field, Object>( 1 > ); > + > + private MockType mockFramework = MockType.EASY_MOCK; > + > + private static Class<?>[] getAnnotatedClasses(Class<?> klass) throws > InitializationError { > + SuiteClasses annotation= klass.getAnnotation(SuiteClasses.class); > + if (annotation == null) > + throw new InitializationError(String.format("class '%s' must > have a SuiteClasses annotation", klass.getName())); > + return annotation.value(); > + } > + > + /** > + * OnamiRunner constructor to create the core JUnice class. > + * > + * @see org.junit.runner.RunWith > + * @param klass The test case class to run. > + * @throws org.junit.runners.model.InitializationError if any error > occurs. > + */ > + public OnamiSuite( Class<?> klass, RunnerBuilder builder ) > + throws InitializationError > + { > + this(builder, klass, getAnnotatedClasses(klass)); > + > + } > + > + /** > + * Called by this class and subclasses once the classes making up the > suite have been determined > + * > + * @param builder builds runners for classes in the suite > + * @param klass the root of the suite > + * @param suiteClasses the classes in the suite > + * @throws InitializationError > + */ > + protected OnamiSuite( RunnerBuilder builder, Class<?> suite, Class<?>[] > suiteClasses ) > + throws InitializationError > + { > + super( suite, runners( suite, suiteClasses ) ); > + try > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( "Inizializing injector for siote class: " + > suite.getName() ); > + } > + > + this.allModules = inizializeInjector( suite ); > + > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( "done..." ); > + } > + } > + catch ( Exception e ) > + { > + final List<Throwable> throwables = new LinkedList<Throwable>(); > + throwables.add( e ); > + throw new InitializationError( throwables ); > + } > + } > + > + /** > + * {@inheritDoc} > + */ > + public void run( final RunNotifier notifier ) > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " ### Run test case: " + > getTestClass().getJavaClass() + " ### " ); > + LOGGER.finer( " #### Creating injector ####" ); > + } > + > + this.injector = createInjector( allModules ); > + super.run( notifier ); > + this.flush(); > + > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " ### End test case: " + > getTestClass().getJavaClass().getName() + " ### " ); > + } > + } > + > + private static List<Runner> runners( Class<?> suite, Class<?>[] children > ) throws InitializationError { > + ArrayList<Runner> runners= new ArrayList<Runner>(); > + for (Class<?> each : children) { > + Runner childRunner= new OnamiRunner( suite, each ); > + if (childRunner != null) > + runners.add(childRunner); > + } > + return runners; > + } > + > + /** > + * {@inheritDoc} > + */ > + private void flush() > + { > + this.injector = null; > + this.allModules.clear(); > + this.mocked.clear(); > + } > + > + @Override > + protected void runChild( Runner runner, RunNotifier notifier ) > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " +++ invoke runner: " + runner + " +++ " ); > + } > + > + super.runChild( runner, notifier ); > + resetAllResetAfterMocks(); > + > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " --- end runner: " + runner + " --- " ); > + } > + } > + > + /** > + * Shortcut to create the Injector given a list of Modules. > + * > + * @param modules the list of modules have to be load > + * @return an Injector instance built using the input Module list > + */ > + protected Injector createInjector( List<Module> modules ) > + { > + return Guice.createInjector( modules ); > + } > + > + /** > + * This method collects modules from {@link GuiceModules}, {@link > GuiceProvidedModules}, {@link Mock}. > + * > + * @param <T> whatever input type is accepted > + * @param clazz the input class has to be analyzed > + * @return a List of Guice Modules built after input class analysis. > + * @throws IllegalAccessException when a n error occurs. > + * @throws InstantiationException when a n error occurs. > + * @throws HandleException when a n error occurs. > + */ > + protected <T> List<Module> inizializeInjector( Class<T> clazz ) > + throws HandleException, InstantiationException, > IllegalAccessException > + { > + final List<Module> modules = new ArrayList<Module>(); > + Module m = visitClass( clazz ); > + if ( m != null ) > + { > + modules.add( m ); > + } > + return modules; > + } > + > + private void resetAllResetAfterMocks() > + { > + for ( Entry<Field, Object> entry : mocked.entrySet() ) > + { > + final Mock mockAnnotation = entry.getKey().getAnnotation( > Mock.class ); > + if ( mockAnnotation.resetAfter() ) > + { > + MockEngine mockEngine = MockEngineFactory.getMockEngine( > mockFramework ); > + mockEngine.resetMock( entry.getValue() ); > + } > + } > + } > + > + /** > + * @throws HandleException > + * @throws IllegalAccessException > + * @throws InstantiationException > + */ > + private <T> Module visitClass( final Class<T> clazz ) > + throws HandleException, InstantiationException, > IllegalAccessException > + { > + try > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " Start introspecting class: " + > clazz.getName() ); > + } > + final List<Module> allModules = new ArrayList<Module>(); > + > + // Setup the handlers > + final GuiceProvidedModuleHandler guiceProvidedModuleHandler = > new GuiceProvidedModuleHandler(); > + final GuiceModuleHandler guiceModuleHandler = new > GuiceModuleHandler(); > + final GuiceInjectableClassHandler<Inject> > guiceInjectableClassHandler = new GuiceInjectableClassHandler<Inject>(); > + final GuiceInjectableClassHandler<javax.inject.Inject> > jsr330InjectableClassHandler = new > GuiceInjectableClassHandler<javax.inject.Inject>(); > + > + final MockHandler mockHandler = new MockHandler(); > + final MockFrameworkHandler mockFrameworkHandler = new > MockFrameworkHandler(); > + > + // Visit class and super-classes > + new ClassVisitor() > + .registerHandler( GuiceProvidedModules.class, > guiceProvidedModuleHandler ) > + .registerHandler( GuiceModules.class, guiceModuleHandler ) > + .registerHandler( Mock.class, mockHandler ) > + .registerHandler( MockFramework.class, mockFrameworkHandler ) > + .registerHandler( Inject.class, guiceInjectableClassHandler ) > + .registerHandler( javax.inject.Inject.class, > jsr330InjectableClassHandler ) > + .visit( clazz ); > + > + // Retrieve mock framework > + if ( mockFrameworkHandler.getMockType() != null ) > + { > + this.mockFramework = mockFrameworkHandler.getMockType(); > + } > + > + // retrieve the modules founded > + allModules.addAll( guiceProvidedModuleHandler.getModules() ); > + allModules.addAll( guiceModuleHandler.getModules() ); > + MockEngine engine = MockEngineFactory.getMockEngine( > this.mockFramework ); > + this.mocked.putAll( mockHandler.getMockedObject( engine ) ); > + if ( !this.mocked.isEmpty() ) > + { > + // Replace all real module binding with Mocked moduled. > + Module m = Modules.override( allModules ).with( new > GuiceMockModule( this.mocked ) ); > + allModules.clear(); > + allModules.add( m ); > + } > + > + // Add only clasess that have got the Inject annotation > + final Class<?>[] guiceInjectableClasses = > guiceInjectableClassHandler.getClasses(); > + final Class<?>[] jsr330InjectableClasses = > jsr330InjectableClassHandler.getClasses(); > + > + final AbstractModule statcInjector = new AbstractModule() > + { > + @Override > + protected void configure() > + { > + // inject all STATIC dependencies > + if ( guiceInjectableClasses.length != 0 ) > + { > + requestStaticInjection( guiceInjectableClasses ); > + } > + > + if ( jsr330InjectableClasses.length != 0 ) > + { > + requestStaticInjection( jsr330InjectableClasses ); > + } > + > + > + } > + }; > + if ( guiceInjectableClasses.length != 0 || > jsr330InjectableClasses.length != 0 ) > + { > + allModules.add( statcInjector ); > + } > + > + // Check if the class is itself a Google Module. > + if ( Module.class.isAssignableFrom( > getTestClass().getJavaClass() ) ) > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " creating module from test class " + > getTestClass().getJavaClass() ); > + } > + final Module classModule = (Module) > getTestClass().getJavaClass().newInstance(); > + allModules.add( classModule ); > + } > + > + // create MockTypeListenerModule > + if ( this.mocked.size() != 0 ) > + { > + final AbstractModule mockTypeListenerModule = new > AbstractModule() > + { > + @Override > + protected void configure() > + { > + bindListener( Matchers.any(), new MockTypeListener( > mocked ) ); > + } > + }; > + > + // BEGIN patch for issue: google-guice: #452 > + for ( Entry<Field, Object> entry : mocked.entrySet() ) > + { > + final Field field = entry.getKey(); > + final Object mock = entry.getValue(); > + if ( Modifier.isStatic( field.getModifiers() ) ) > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " inject static mock field: " + > field.getName() ); > + } > + > + field.setAccessible( true ); > + field.set( field.getDeclaringClass(), mock ); > + } > + } > + // END patch for issue: google-guice: #452 > + > + allModules.add( mockTypeListenerModule ); > + } > + > + if ( allModules.size() != 0 ) > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + StringBuilder builder = new StringBuilder(); > + builder.append( " Collected modules: " ); > + builder.append( "\n" ); > + for ( Module module : allModules ) > + { > + builder.append( " " + module ); > + builder.append( "\n" ); > + } > + LOGGER.finer( builder.toString() ); > + } > + return Modules.combine( allModules ); > + } > + return null; > + } > + finally > + { > + if ( LOGGER.isLoggable( Level.FINER ) ) > + { > + LOGGER.finer( " ...done" ); > + } > + } > + } > + > +} > > Added: > incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java > URL: > http://svn.apache.org/viewvc/incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java?rev=1455170&view=auto > ============================================================================== > --- > incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java > (added) > +++ > incubator/onami/trunk/test/src/test/java/org/apache/onami/test/OnamiSuiteTest.java > Mon Mar 11 15:12:05 2013 > @@ -0,0 +1,10 @@ > +package org.apache.onami.test; > + > +import org.junit.runner.RunWith; > +import org.junit.runners.Suite.SuiteClasses; > + > +@RunWith(OnamiSuite.class) > +@SuiteClasses({ InjectDependingMockObjectTestCase.class, > InjectFromSuperClassTestCase.class }) > +public class OnamiSuiteTest { > + > +} > >