1 package com.xtremelabs.robolectric.bytecode; 2 3 import javassist.ClassPool; 4 import javassist.CtClass; 5 import org.junit.Before; 6 import org.junit.Test; 7 8 import static org.junit.Assert.*; 9 import static org.mockito.Matchers.any; 10 import static org.mockito.Matchers.anyObject; 11 import static org.mockito.Matchers.eq; 12 import static org.mockito.Mockito.*; 13 14 public class AndroidTranslatorUnitTest { 15 private ClassPool classPool; 16 private AndroidTranslator androidTranslator; 17 18 @Before public void setUp() throws Exception { 19 classPool = new ClassPool(true); 20 androidTranslator = new AndroidTranslator(null, null); 21 } 22 23 @Test 24 public void whenMethodReturnsObject_shouldGenerateMethodBody() throws Exception { 25 CtClass ctClass = classPool.get("java.lang.String"); 26 String methodBody = androidTranslator.generateMethodBody( 27 ctClass, ctClass.getDeclaredMethod("substring", new CtClass[]{CtClass.intType}), 28 ctClass, Type.OBJECT, false, false); 29 assertEquals("if (!com.xtremelabs.robolectric.bytecode.RobolectricInternals.shouldCallDirectly(this)) {\n" + 30 "Object x = com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(\n" + 31 " java.lang.String.class, \"substring\", this, new String[] {\"int\"}, new Object[] {com.xtremelabs.robolectric.bytecode.RobolectricInternals.autobox($1)});\n" + 32 "if (x != null) return ((java.lang.String) x);\n" + 33 "return null;\n" + 34 "}\n", methodBody); 35 } 36 37 @Test 38 public void whenMethodReturnsPrimitive_shouldGenerateMethodBody() throws Exception { 39 CtClass ctClass = classPool.get("java.lang.String"); 40 String methodBody = androidTranslator.generateMethodBody( 41 ctClass, ctClass.getDeclaredMethod("length"), 42 ctClass, Type.OBJECT, false, false); 43 assertEquals("if (!com.xtremelabs.robolectric.bytecode.RobolectricInternals.shouldCallDirectly(this)) {\n" + 44 "Object x = com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(\n" + 45 " java.lang.String.class, \"length\", this, new String[0], new Object[0]);\n" + 46 "if (x != null) return ((java.lang.String) x);\n" + 47 "return null;\n" + 48 "}\n", methodBody); 49 } 50 51 @Test 52 public void whenMethodReturnsVoid_shouldGenerateMethodBody() throws Exception { 53 CtClass ctClass = classPool.get("java.lang.Object"); 54 String methodBody = androidTranslator.generateMethodBody( 55 ctClass, ctClass.getDeclaredMethod("wait"), 56 ctClass, Type.VOID, false, false); 57 assertEquals("if (!com.xtremelabs.robolectric.bytecode.RobolectricInternals.shouldCallDirectly(this)) {\n" + 58 "com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(\n" + 59 " java.lang.Object.class, \"wait\", this, new String[] {\"long\"}, new Object[] {com.xtremelabs.robolectric.bytecode.RobolectricInternals.autobox($1)});\n" + 60 "return;\n" + 61 "}\n", methodBody); 62 } 63 64 @Test 65 public void whenMethodIsStatic_shouldGenerateMethodBody() throws Exception { 66 CtClass ctClass = classPool.get("java.lang.String"); 67 String methodBody = androidTranslator.generateMethodBody( 68 ctClass, ctClass.getDeclaredMethod("valueOf", new CtClass[]{CtClass.intType}), 69 ctClass, Type.OBJECT, true, false); 70 assertEquals("if (!com.xtremelabs.robolectric.bytecode.RobolectricInternals.shouldCallDirectly(java.lang.String.class)) {\n" + 71 "Object x = com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(\n" + 72 " java.lang.String.class, \"valueOf\", null, new String[] {\"int\"}, new Object[] {com.xtremelabs.robolectric.bytecode.RobolectricInternals.autobox($1)});\n" + 73 "if (x != null) return ((java.lang.String) x);\n" + 74 "return null;\n" + 75 "}\n", methodBody); 76 } 77 78 @Test 79 public void shouldGenerateParameterList() throws Exception { 80 assertEquals(androidTranslator.makeParameterReplacementList(0), ""); 81 assertEquals(androidTranslator.makeParameterReplacementList(1), "$1"); 82 assertEquals(androidTranslator.makeParameterReplacementList(2), "$1, $2"); 83 } 84 85 @Test 86 public void shouldGenerateMethodBodyForEquals() throws Exception { 87 CtClass ctClass = classPool.get("java.lang.Object"); 88 String methodBody = androidTranslator.generateMethodBody( 89 ctClass, ctClass.getDeclaredMethod("equals", new CtClass[]{ctClass}), 90 ctClass, Type.BOOLEAN, false, true); 91 assertEquals("if (!com.xtremelabs.robolectric.bytecode.RobolectricInternals.shouldCallDirectly(this)) {\n" + 92 "Object x = com.xtremelabs.robolectric.bytecode.RobolectricInternals.methodInvoked(\n" + 93 " java.lang.Object.class, \"equals\", this, new String[] {\"java.lang.Object\"}, new Object[] {com.xtremelabs.robolectric.bytecode.RobolectricInternals.autobox($1)});\n" + 94 "if (x != null) return ((java.lang.Boolean) x).booleanValue();\n" + 95 "return super.equals($1);}\n", methodBody); 96 } 97 98 @Test 99 public void shouldInstrumentDefaultRequestDirector() throws Exception { 100 assertTrue(androidTranslator.shouldInstrument(classPool.makeClass("org.apache.http.impl.client.DefaultRequestDirector"))); 101 } 102 103 @Test 104 public void shouldInstrumentGoogleMapsClasses() throws Exception { 105 assertTrue(androidTranslator.shouldInstrument(classPool.makeClass("com.google.android.maps.SomeMapsClass"))); 106 } 107 108 @Test 109 public void shouldNotInstrumentCoreJdkClasses() throws Exception { 110 assertFalse(androidTranslator.shouldInstrument(classPool.get("java.lang.Object"))); 111 assertFalse(androidTranslator.shouldInstrument(classPool.get("java.lang.String"))); 112 } 113 114 @Test 115 public void shouldInstumentAndroidCoreClasses() throws Exception { 116 assertTrue(androidTranslator.shouldInstrument(classPool.makeClass("android.content.Intent"))); 117 assertTrue(androidTranslator.shouldInstrument(classPool.makeClass("android.and.now.for.something.completely.different"))); 118 119 } 120 121 @Test 122 public void shouldNotInstrumentLocalBroadcastManager() throws Exception { 123 assertFalse(androidTranslator.shouldInstrument(classPool.makeClass("android.support.v4.content.LocalBroadcastManager"))); 124 } 125 126 @Test 127 public void shouldAddCustomShadowClass() throws Exception { 128 androidTranslator.addCustomShadowClass("my.custom.Klazz"); 129 assertTrue(androidTranslator.shouldInstrument(classPool.makeClass("my.custom.Klazz"))); 130 } 131 132 @Test 133 public void testOnLoadWithNonInstrumentedClass() throws Exception { 134 ClassHandler handler = mock(ClassHandler.class); 135 ClassCache cache = mock(ClassCache.class); 136 137 AndroidTranslator translator = new AndroidTranslator(handler, cache); 138 139 translator.onLoad(classPool, "java.lang.Object"); 140 verify(cache).isWriting(); 141 verifyNoMoreInteractions(cache); 142 verifyZeroInteractions(handler); 143 } 144 145 @Test(expected = IllegalStateException.class) 146 public void shouldThrowIllegalStateIfClassCacheIsWriting() throws Exception { 147 ClassCache cache = mock(ClassCache.class); 148 when(cache.isWriting()).thenReturn(true); 149 new AndroidTranslator(null, cache).onLoad(classPool, "java.lang.Object"); 150 } 151 } 152