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@google.com (Stephen Woodward) 51 */ 52 public class UsesMocksProcessorTest extends TestCase { 53 getAnnotatedElementsSet(Class<?>.... classes)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") getMockElement(Class<?> clazz)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") getMockAnnotationMirrors(Class<?> clazz)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") getMockElementValuesMap(Class<?> clazz)84 private Map getMockElementValuesMap(Class<?> clazz) { 85 Map mockValuesMap = new HashMap(); 86 mockValuesMap.put(getMockExecutableElement(), getMockAnnotationValue(clazz)); 87 return mockValuesMap; 88 } 89 getMockAnnotationValue(Class<?> clazz)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 getMockExecutableElement()98 private ExecutableElement getMockExecutableElement() { 99 ExecutableElement mockElement = EasyMock.createNiceMock(ExecutableElement.class); 100 EasyMock.replay(mockElement); 101 return mockElement; 102 } 103 getMockAnnotationType()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