Coverage Report - org.apache.onami.test.GuiceMockModule
 
Classes in this File Line Coverage Branch Coverage Complexity
GuiceMockModule
87%
43/49
87%
28/32
7
 
 1  
 package org.apache.onami.test;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import static com.google.common.base.Preconditions.checkState;
 23  
 
 24  
 import java.lang.reflect.Field;
 25  
 import java.lang.reflect.Type;
 26  
 import java.util.ArrayList;
 27  
 import java.util.Collection;
 28  
 import java.util.List;
 29  
 import java.util.Map;
 30  
 import java.util.Map.Entry;
 31  
 import java.util.logging.Level;
 32  
 import java.util.logging.Logger;
 33  
 
 34  
 import org.apache.onami.test.annotation.Mock;
 35  
 
 36  
 import com.google.common.collect.HashMultimap;
 37  
 import com.google.common.collect.Multimap;
 38  
 import com.google.inject.AbstractModule;
 39  
 import com.google.inject.TypeLiteral;
 40  
 import com.google.inject.name.Names;
 41  
 
 42  
 /**
 43  
  * <p>
 44  
  * This class creates the binding for all mock objects found.
 45  
  * </p>
 46  
  * <p>
 47  
  * Method {@link GuiceMockModule#configure()} creates a binding for each {@link Mock} annotation found. The binding will
 48  
  * be created <b>if and only if</b> there is no types conflict between {@link Mock} caught.
 49  
  * <p>
 50  
  * <p>
 51  
  * <b>A type conflict</b> is detected if two or more field are annotated with the same {@link Mock} and no different
 52  
  * {@link Mock#annotatedWith} parameter are specified, or two o more equals {@link Mock#annotatedWith} parameter are
 53  
  * specified for the same type field.
 54  
  * </p>
 55  
  * <p>
 56  
  * If a conflict is detected the binding will not create for the conflicted type, moreover the field will be injected
 57  
  * into the test class.
 58  
  * </p>
 59  
  */
 60  
 public class GuiceMockModule
 61  
     extends AbstractModule
 62  
 {
 63  
 
 64  1
     private static final Logger LOGGER = Logger.getLogger( GuiceMockModule.class.getName() );
 65  
 
 66  
     final Map<Field, Object> mockedFields;
 67  
 
 68  
     /**
 69  
      * Costructor.
 70  
      *
 71  
      * @param mockedFields the map of mock fileds.
 72  
      */
 73  
 
 74  
     public GuiceMockModule( final Map<Field, Object> mockedFields )
 75  7
     {
 76  7
         this.mockedFields = mockedFields;
 77  7
     }
 78  
 
 79  
     @SuppressWarnings( "unchecked" )
 80  
     @Override
 81  
     protected void configure()
 82  
     {
 83  7
         final Multimap<Type, Field> fieldsByType = HashMultimap.create();
 84  
 
 85  7
         for ( final Entry<Field, Object> entry : this.mockedFields.entrySet() )
 86  
         {
 87  11
             fieldsByType.put( entry.getKey().getGenericType(), entry.getKey() );
 88  
         }
 89  
 
 90  7
         for ( final Type type : fieldsByType.keySet() )
 91  
         {
 92  9
             final Collection<Field> fields = fieldsByType.get( type );
 93  
 
 94  9
             boolean isTypeConflicts = false;
 95  9
             if ( fields.size() != 1 )
 96  
             {
 97  1
                 isTypeConflicts = checkTypeConflict( fields );
 98  
             }
 99  
 
 100  9
             checkState( !isTypeConflicts, "   Found multiple annotation @%s for type: %s; binding skipped!.",
 101  
                         Mock.class.getSimpleName(), type );
 102  9
             for ( final Field field : fields )
 103  
             {
 104  11
                 final TypeLiteral literal = TypeLiteral.get( type );
 105  11
                 final Mock annoBy = field.getAnnotation( Mock.class );
 106  11
                 final Object mock = this.mockedFields.get( field );
 107  11
                 if ( annoBy.annotatedWith() != Mock.NoAnnotation.class )
 108  
                 {
 109  1
                     bind( literal ).annotatedWith( annoBy.annotatedWith() ).toInstance( mock );
 110  
                 }
 111  10
                 else if ( !"".equals( annoBy.namedWith() ) )
 112  
                 {
 113  1
                     bind( literal ).annotatedWith( Names.named( annoBy.namedWith() ) ).toInstance( mock );
 114  
                 }
 115  
                 else
 116  
                 {
 117  9
                     bind( literal ).toInstance( mock );
 118  
                 }
 119  11
                 if ( LOGGER.isLoggable( Level.FINER ) )
 120  
                 {
 121  6
                     LOGGER.finer( "    Created binding for: " + type + " " + annoBy );
 122  
                 }
 123  11
             }
 124  9
         }
 125  7
     }
 126  
 
 127  
     /**
 128  
      * @param fields
 129  
      * @return
 130  
      */
 131  
     private boolean checkTypeConflict( Collection<Field> fields )
 132  
     {
 133  1
         final List<Class<?>> listAnnotatedType = new ArrayList<Class<?>>();
 134  1
         final List<String> listNamedType = new ArrayList<String>();
 135  1
         int numOfSimpleType = 0;
 136  
 
 137  1
         for ( Field field : fields )
 138  
         {
 139  3
             final Mock annoBy = field.getAnnotation( Mock.class );
 140  
 
 141  3
             if ( annoBy.annotatedWith() == Mock.NoAnnotation.class && "".equals( annoBy.namedWith() ) )
 142  
             {
 143  1
                 numOfSimpleType++;
 144  
             }
 145  3
             if ( numOfSimpleType > 1 )
 146  
             {
 147  0
                 LOGGER.finer( "Found multiple simple type" );
 148  0
                 return true;
 149  
             }
 150  
 
 151  3
             if ( annoBy.annotatedWith() != Mock.NoAnnotation.class )
 152  
             {
 153  1
                 if ( !listAnnotatedType.contains( annoBy.annotatedWith() ) )
 154  
                 {
 155  1
                     listAnnotatedType.add( annoBy.annotatedWith() );
 156  
                 }
 157  
                 else
 158  
                 {
 159  
                     // found two fields with same annotation
 160  0
                     LOGGER.finer( "Found multiple annotatedBy type" );
 161  0
                     return true;
 162  
                 }
 163  
             }
 164  
 
 165  3
             if ( !"".equals( annoBy.namedWith() ) )
 166  
             {
 167  1
                 if ( !listNamedType.contains( annoBy.namedWith() ) )
 168  
                 {
 169  1
                     listNamedType.add( annoBy.namedWith() );
 170  
                 }
 171  
                 else
 172  
                 {
 173  
                     // found two fields with same named annotation
 174  0
                     LOGGER.finer( "Found multiple namedWith type" );
 175  0
                     return true;
 176  
                 }
 177  
             }
 178  3
         }
 179  1
         return false;
 180  
     }
 181  
 
 182  
 }