Home | History | Annotate | Download | only in mocking
      1 /*
      2  * Copyright 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy of
      6  * the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations under
     14  * the License.
     15  */
     16 package com.google.android.testing.mocking;
     17 
     18 import javassist.CannotCompileException;
     19 
     20 import junit.framework.TestCase;
     21 
     22 import org.easymock.EasyMock;
     23 
     24 import java.io.ByteArrayOutputStream;
     25 import java.io.IOException;
     26 import java.io.OutputStream;
     27 import java.util.ArrayList;
     28 import java.util.Arrays;
     29 import java.util.HashMap;
     30 import java.util.HashSet;
     31 import java.util.List;
     32 import java.util.Map;
     33 import java.util.Set;
     34 
     35 import javax.annotation.processing.Filer;
     36 import javax.annotation.processing.Messager;
     37 import javax.annotation.processing.ProcessingEnvironment;
     38 import javax.annotation.processing.RoundEnvironment;
     39 import javax.lang.model.element.AnnotationMirror;
     40 import javax.lang.model.element.AnnotationValue;
     41 import javax.lang.model.element.Element;
     42 import javax.lang.model.element.ExecutableElement;
     43 import javax.lang.model.type.DeclaredType;
     44 import javax.lang.model.type.TypeKind;
     45 import javax.lang.model.type.TypeMirror;
     46 import javax.lang.model.type.TypeVisitor;
     47 import javax.tools.JavaFileObject;
     48 
     49 /**
     50  * @author swoodward (at) google.com (Stephen Woodward)
     51  */
     52 public class UsesMocksProcessorTest extends TestCase {
     53 
     54   private Set<? extends Element> getAnnotatedElementsSet(Class<?>... classes) {
     55     Set<Element> set = new HashSet<Element>();
     56     for (Class<?> clazz : classes) {
     57       set.add(getMockElement(clazz));
     58     }
     59     return set;
     60   }
     61 
     62   @SuppressWarnings("unchecked")
     63   private Element getMockElement(Class<?> clazz) {
     64     Element mockElement = EasyMock.createNiceMock(Element.class);
     65     EasyMock.expect(mockElement.getAnnotationMirrors()).andReturn(getMockAnnotationMirrors(clazz))
     66         .anyTimes();
     67     EasyMock.replay(mockElement);
     68     return mockElement;
     69   }
     70 
     71   @SuppressWarnings("unchecked")
     72   private List getMockAnnotationMirrors(Class<?> clazz) {
     73     List<AnnotationMirror> mockMirrorList = new ArrayList<AnnotationMirror>();
     74     AnnotationMirror mockMirror = EasyMock.createNiceMock(AnnotationMirror.class);
     75     EasyMock.expect(mockMirror.getAnnotationType()).andReturn(getMockAnnotationType()).anyTimes();
     76     EasyMock.expect(mockMirror.getElementValues()).andReturn(getMockElementValuesMap(clazz))
     77         .anyTimes();
     78     EasyMock.replay(mockMirror);
     79     mockMirrorList.add(mockMirror);
     80     return mockMirrorList;
     81   }
     82 
     83   @SuppressWarnings("unchecked")
     84   private Map getMockElementValuesMap(Class<?> clazz) {
     85     Map mockValuesMap = new HashMap();
     86     mockValuesMap.put(getMockExecutableElement(), getMockAnnotationValue(clazz));
     87     return mockValuesMap;
     88   }
     89 
     90   private AnnotationValue getMockAnnotationValue(Class<?> clazz) {
     91     AnnotationValue mockValue = EasyMock.createMock(AnnotationValue.class);
     92     EasyMock.expect(mockValue.getValue()).andReturn(
     93         Arrays.asList(new String[] {clazz.getName() + ".class"})).anyTimes();
     94     EasyMock.replay(mockValue);
     95     return mockValue;
     96   }
     97 
     98   private ExecutableElement getMockExecutableElement() {
     99     ExecutableElement mockElement = EasyMock.createNiceMock(ExecutableElement.class);
    100     EasyMock.replay(mockElement);
    101     return mockElement;
    102   }
    103 
    104   private DeclaredType getMockAnnotationType() {
    105     return new DeclaredType() {
    106       @Override
    107       public String toString() {
    108         return UsesMocks.class.getName();
    109       }
    110 
    111       @Override
    112       public Element asElement() {
    113         return null;
    114       }
    115 
    116       @Override
    117       public TypeMirror getEnclosingType() {
    118         return null;
    119       }
    120 
    121       @Override
    122       public List<? extends TypeMirror> getTypeArguments() {
    123         return null;
    124       }
    125 
    126       @Override
    127       public <R, P> R accept(TypeVisitor<R, P> v, P p) {
    128         return null;
    129       }
    130 
    131       @Override
    132       public TypeKind getKind() {
    133         return null;
    134       }
    135     };
    136   }
    137 
    138   private UsesMocksProcessor getProcessor() {
    139     return getProcessor(getMockProcessingEnvironment());
    140   }
    141 
    142   private UsesMocksProcessor getProcessor(ProcessingEnvironment processingEnv) {
    143     UsesMocksProcessor processor = new UsesMocksProcessor();
    144     processor.init(processingEnv);
    145     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    146     processor.logger = new ProcessorLogger(outputStream, processingEnv);
    147     return processor;
    148   }
    149 
    150   private ProcessingEnvironment getMockProcessingEnvironment(Filer mockFiler) {
    151     ProcessingEnvironment mockEnvironment = EasyMock.createNiceMock(ProcessingEnvironment.class);
    152     EasyMock.expect(mockEnvironment.getMessager()).andReturn(getMockMessager()).anyTimes();
    153     EasyMock.expect(mockEnvironment.getFiler()).andReturn(mockFiler).anyTimes();
    154     EasyMock.expect(mockEnvironment.getOptions()).andReturn(getMockOptions()).anyTimes();
    155     EasyMock.replay(mockEnvironment);
    156     return mockEnvironment;
    157   }
    158 
    159   private Map<String, String> getMockOptions() {
    160     Map<String, String> map = new HashMap<String, String>();
    161     map.put("bin_dir", ".");
    162     map.put("logfile", "logfile");
    163     return map;
    164   }
    165 
    166   private ProcessingEnvironment getMockProcessingEnvironment() {
    167     return getMockProcessingEnvironment(getMockFiler());
    168   }
    169 
    170   private Messager getMockMessager() {
    171     Messager mockMessager = EasyMock.createNiceMock(Messager.class);
    172     EasyMock.replay(mockMessager);
    173     return mockMessager;
    174   }
    175 
    176   private Filer getMockFiler() {
    177     try {
    178       return getMockFiler(getMockFileObject());
    179     } catch (IOException e) {
    180       // Can't happen
    181       throw new RuntimeException(e);
    182     }
    183   }
    184 
    185   private Filer getMockFiler(JavaFileObject mockFileObject) {
    186     Filer mockFiler = EasyMock.createNiceMock(Filer.class);
    187     try {
    188       EasyMock.expect(mockFiler.createClassFile((CharSequence) EasyMock.anyObject())).andReturn(
    189           mockFileObject).anyTimes();
    190     } catch (IOException e) {
    191       // Can't happen
    192       throw new RuntimeException(e);
    193     }
    194     EasyMock.replay(mockFiler);
    195     return mockFiler;
    196   }
    197 
    198   private JavaFileObject getMockFileObject() throws IOException {
    199     return getMockFileObject(new ByteArrayOutputStream());
    200   }
    201 
    202   private JavaFileObject getMockFileObject(OutputStream outStream) throws IOException {
    203     JavaFileObject mockFileObject = EasyMock.createNiceMock(JavaFileObject.class);
    204     EasyMock.expect(mockFileObject.openOutputStream()).andReturn(outStream).anyTimes();
    205     EasyMock.replay(mockFileObject);
    206     return mockFileObject;
    207   }
    208 
    209   private RoundEnvironment getMockRoundEnvironment(Set<? extends Element> elementsWithAnnotation) {
    210     return getMockRoundEnvironment(elementsWithAnnotation, false);
    211   }
    212 
    213   @SuppressWarnings("unchecked")
    214   private RoundEnvironment getMockRoundEnvironment(Set<? extends Element> elementsWithAnnotation,
    215       boolean finishedProcessing) {
    216     RoundEnvironment mockEnv = EasyMock.createNiceMock(RoundEnvironment.class);
    217     EasyMock.expect(mockEnv.getElementsAnnotatedWith(UsesMocks.class)).andReturn(
    218         (Set) elementsWithAnnotation).anyTimes();
    219     EasyMock.expect(mockEnv.processingOver()).andReturn(finishedProcessing).anyTimes();
    220     EasyMock.replay(mockEnv);
    221     return mockEnv;
    222   }
    223 
    224   public void testGetClassMocks() throws IOException, CannotCompileException {
    225     List<Class<?>> classesToMock = new ArrayList<Class<?>>();
    226     classesToMock.add(TestCase.class);
    227     List<String> expectedMocks =
    228         new ArrayList<String>(Arrays.asList(new String[] {
    229             "genmocks." + TestCase.class.getName() + "DelegateInterface",
    230             "genmocks." + TestCase.class.getName() + "DelegateSubclass"}));
    231     Set<GeneratedClassFile> mockedClasses =
    232         getProcessor().getClassMocks(classesToMock, true);
    233 
    234     assertEquals(2, mockedClasses.size());
    235     for (GeneratedClassFile clazz : mockedClasses) {
    236       assertTrue(expectedMocks.contains(clazz.getClassName()));
    237       expectedMocks.remove(clazz.getClassName());
    238     }
    239   }
    240 
    241   public void testWriteMocks() throws IOException, CannotCompileException {
    242     List<Class<?>> classesToMock = new ArrayList<Class<?>>();
    243     classesToMock.add(TestCase.class);
    244     Set<GeneratedClassFile> mockedClassesSet =
    245         getProcessor().getClassMocks(classesToMock, true);
    246     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    247 
    248     getProcessor(getMockProcessingEnvironment(getMockFiler(getMockFileObject(outputStream))))
    249         .writeMocks(mockedClassesSet);
    250 
    251     String output = new String(outputStream.toByteArray());
    252     for (GeneratedClassFile mockClass : mockedClassesSet) {
    253       String expected = new String(mockClass.getContents());
    254       assertTrue(output.contains(expected));
    255       output = output.replace(expected, "");
    256     }
    257     assertEquals(0, output.length());
    258   }
    259 
    260   public void testProcess() {
    261     assertFalse(getProcessor().process(null,
    262         getMockRoundEnvironment(getAnnotatedElementsSet(TestCase.class))));
    263     assertFalse(getProcessor().process(null,
    264         getMockRoundEnvironment(getAnnotatedElementsSet(TestCase.class), true)));
    265   }
    266 
    267   public void testFindClassesToMock() {
    268     Set<? extends Element> annotatedElements = getAnnotatedElementsSet(Set.class, TestCase.class);
    269     List<Class<?>> classesList = getProcessor().findClassesToMock(annotatedElements);
    270 
    271     assertEquals(annotatedElements.size(), classesList.size());
    272     assertTrue(classesList.contains(Set.class));
    273     assertTrue(classesList.contains(TestCase.class));
    274   }
    275 }
    276