1 package org.robolectric.annotation.processing; 2 3 import static com.google.common.truth.Truth.assertAbout; 4 import static com.google.common.truth.Truth.assertThat; 5 import static com.google.testing.compile.JavaFileObjects.forResource; 6 import static com.google.testing.compile.JavaFileObjects.forSourceString; 7 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; 8 import static java.nio.charset.StandardCharsets.UTF_8; 9 import static org.robolectric.annotation.processing.RobolectricProcessor.JSON_DOCS_DIR; 10 import static org.robolectric.annotation.processing.RobolectricProcessor.PACKAGE_OPT; 11 import static org.robolectric.annotation.processing.RobolectricProcessor.SHOULD_INSTRUMENT_PKG_OPT; 12 import static org.robolectric.annotation.processing.Utils.DEFAULT_OPTS; 13 import static org.robolectric.annotation.processing.Utils.SHADOW_EXTRACTOR_SOURCE; 14 import static org.robolectric.annotation.processing.Utils.SHADOW_PROVIDER_SOURCE; 15 16 import com.google.common.collect.ImmutableList; 17 import com.google.common.collect.ImmutableMap; 18 import com.google.common.io.Files; 19 import java.io.BufferedReader; 20 import java.io.IOException; 21 import java.io.InputStream; 22 import java.io.InputStreamReader; 23 import java.util.HashMap; 24 import java.util.Map; 25 import org.junit.Test; 26 import org.junit.runner.RunWith; 27 import org.junit.runners.JUnit4; 28 29 @RunWith(JUnit4.class) 30 public class RobolectricProcessorTest { 31 @Test 32 public void robolectricProcessor_supportsPackageOption() { 33 assertThat(new RobolectricProcessor(DEFAULT_OPTS).getSupportedOptions()).contains(PACKAGE_OPT); 34 } 35 36 @Test 37 public void robolectricProcessor_supportsShouldInstrumentPackageOption() { 38 assertThat( 39 new RobolectricProcessor(DEFAULT_OPTS).getSupportedOptions()).contains(SHOULD_INSTRUMENT_PKG_OPT); 40 } 41 42 @Test 43 public void unannotatedSource_shouldCompile() { 44 assertAbout(javaSources()) 45 .that(ImmutableList.of( 46 SHADOW_PROVIDER_SOURCE, 47 SHADOW_EXTRACTOR_SOURCE, 48 forSourceString("HelloWorld", "final class HelloWorld {}"))) 49 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 50 .compilesWithoutError(); 51 //.and().generatesNoSources(); Should add this assertion onces 52 // it becomes available in compile-testing 53 } 54 55 @Test 56 public void generatedFile_shouldHandleInnerClassCollisions() { 57 // Because the Generated annotation has a retention of "source", it can't 58 // be tested by a unit test - must run a source-level test. 59 assertAbout(javaSources()) 60 .that(ImmutableList.of( 61 SHADOW_PROVIDER_SOURCE, 62 SHADOW_EXTRACTOR_SOURCE, 63 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"), 64 forResource("org/robolectric/annotation/processing/shadows/ShadowOuterDummy.java"), 65 forResource("org/robolectric/annotation/processing/shadows/ShadowUniqueDummy.java"))) 66 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 67 .compilesWithoutError() 68 .and() 69 .generatesSources(forResource("org/robolectric/Robolectric_InnerClassCollision.java")); 70 } 71 72 @Test 73 public void generatedFile_shouldHandleNonPublicClasses() { 74 assertAbout(javaSources()) 75 .that(ImmutableList.of( 76 SHADOW_PROVIDER_SOURCE, 77 SHADOW_EXTRACTOR_SOURCE, 78 forResource("org/robolectric/annotation/processing/shadows/ShadowPrivate.java"), 79 forResource("org/robolectric/annotation/processing/shadows/ShadowOuterDummy2.java"), 80 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) 81 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 82 .compilesWithoutError() 83 .and() 84 .generatesSources(forResource("org/robolectric/Robolectric_HiddenClasses.java")); 85 } 86 87 @Test 88 public void generatedFile_shouldComplainAboutNonStaticInnerClasses() { 89 assertAbout(javaSources()) 90 .that(ImmutableList.of( 91 SHADOW_PROVIDER_SOURCE, 92 SHADOW_EXTRACTOR_SOURCE, 93 forResource("org/robolectric/annotation/processing/shadows/ShadowOuterDummyWithErrs.java"))) 94 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 95 .failsToCompile() 96 .withErrorContaining("inner shadow classes must be static"); 97 } 98 99 @Test 100 public void generatedFile_shouldHandleClassNameOnlyShadows() { 101 assertAbout(javaSources()) 102 .that(ImmutableList.of( 103 SHADOW_PROVIDER_SOURCE, 104 SHADOW_EXTRACTOR_SOURCE, 105 forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), 106 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) 107 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 108 .compilesWithoutError() 109 .and() 110 .generatesSources(forResource("org/robolectric/Robolectric_ClassNameOnly.java")); 111 } 112 113 @Test 114 public void generatedFile_shouldNotGenerateShadowOfMethodsForExcludedClasses() { 115 assertAbout(javaSources()) 116 .that(ImmutableList.of( 117 SHADOW_PROVIDER_SOURCE, 118 SHADOW_EXTRACTOR_SOURCE, 119 forResource("org/robolectric/annotation/processing/shadows/ShadowExcludedFromAndroidSdk.java"))) 120 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 121 .compilesWithoutError() 122 .and() 123 .generatesSources(forResource("org/robolectric/Robolectric_NoExcludedTypes.java")); 124 } 125 126 @Test 127 public void generatedFile_shouldUseSpecifiedPackage() throws IOException { 128 StringBuilder expected = new StringBuilder(); 129 InputStream in = RobolectricProcessorTest.class.getClassLoader() 130 .getResourceAsStream("org/robolectric/Robolectric_ClassNameOnly.java"); 131 BufferedReader reader = new BufferedReader(new InputStreamReader(in, UTF_8)); 132 133 String line; 134 while ((line = reader.readLine()) != null) { 135 expected.append(line).append("\n"); 136 } 137 line = expected.toString(); 138 line = line.replace("package org.robolectric", "package my.test.pkg"); 139 140 ImmutableMap<String, String> opts = 141 ImmutableMap.of( 142 PACKAGE_OPT, "my.test.pkg", JSON_DOCS_DIR, Files.createTempDir().toString()); 143 144 assertAbout(javaSources()) 145 .that(ImmutableList.of( 146 SHADOW_PROVIDER_SOURCE, 147 SHADOW_EXTRACTOR_SOURCE, 148 forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), 149 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) 150 .processedWith(new RobolectricProcessor(opts)) 151 .compilesWithoutError() 152 .and() 153 .generatesSources(forSourceString("Shadows", line)); 154 } 155 156 @Test 157 public void shouldGenerateMetaInfServicesFile() { 158 assertAbout(javaSources()) 159 .that(ImmutableList.of( 160 SHADOW_PROVIDER_SOURCE, 161 SHADOW_EXTRACTOR_SOURCE, 162 forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), 163 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) 164 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 165 .compilesWithoutError() 166 .and() 167 .generatesFiles(forResource("META-INF/services/org.robolectric.internal.ShadowProvider")); 168 } 169 170 @Test 171 public void shouldGracefullyHandleUnrecognisedAnnotation() { 172 assertAbout(javaSources()) 173 .that(ImmutableList.of( 174 SHADOW_PROVIDER_SOURCE, 175 SHADOW_EXTRACTOR_SOURCE, 176 forResource("org/robolectric/annotation/TestWithUnrecognizedAnnotation.java"))) 177 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 178 .compilesWithoutError(); 179 } 180 181 @Test 182 public void shouldGenerateGenericShadowOf() { 183 assertAbout(javaSources()) 184 .that(ImmutableList.of( 185 SHADOW_PROVIDER_SOURCE, 186 SHADOW_EXTRACTOR_SOURCE, 187 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"), 188 forResource("org/robolectric/annotation/processing/shadows/ShadowParameterizedDummy.java"))) 189 .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) 190 .compilesWithoutError() 191 .and() 192 .generatesSources(forResource("org/robolectric/Robolectric_Parameterized.java")); 193 } 194 195 @Test 196 public void generatedShadowProvider_canConfigureInstrumentingPackages() { 197 Map<String, String> options = new HashMap<>(DEFAULT_OPTS); 198 options.put(SHOULD_INSTRUMENT_PKG_OPT, "false"); 199 200 assertAbout(javaSources()) 201 .that(ImmutableList.of( 202 SHADOW_PROVIDER_SOURCE, 203 SHADOW_EXTRACTOR_SOURCE, 204 forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) 205 .processedWith(new RobolectricProcessor(options)) 206 .compilesWithoutError() 207 .and() 208 .generatesSources(forResource("org/robolectric/Robolectric_EmptyProvidedPackageNames.java")); 209 } 210 } 211