package org.robolectric.annotation.processing; import static com.google.common.truth.Truth.assertThat; import static org.truth0.Truth.ASSERT; import static com.google.testing.compile.JavaFileObjects.*; import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; import static org.robolectric.annotation.processing.RobolectricProcessor.PACKAGE_OPT; import static org.robolectric.annotation.processing.RobolectricProcessor.SHOULD_INSTRUMENT_PKG_OPT; import static org.robolectric.annotation.processing.validator.Utils.ROBO_SOURCE; import static org.robolectric.annotation.processing.validator.Utils.SHADOW_PROVIDER_SOURCE; import static org.robolectric.annotation.processing.validator.Utils.SHADOW_EXTRACTOR_SOURCE; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.util.HashMap; import java.util.Map; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import org.junit.Test; import com.google.common.collect.ImmutableList; public class RobolectricProcessorTest { private static final Map<String,String> DEFAULT_OPTS = new HashMap<>(); static { DEFAULT_OPTS.put(PACKAGE_OPT, "org.robolectric"); } @Test public void robolectricProcessor_supportsPackageOption() { ASSERT.that(new RobolectricProcessor().getSupportedOptions()).contains(PACKAGE_OPT); } @Test public void robolectricProcessor_supportsShouldInstrumentPackageOption() { ASSERT.that( new RobolectricProcessor().getSupportedOptions()).contains(SHOULD_INSTRUMENT_PKG_OPT); } @Test public void unannotatedSource_shouldCompile() { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forSourceString("HelloWorld", "final class HelloWorld {}"))) .processedWith(new RobolectricProcessor()) .compilesWithoutError(); //.and().generatesNoSources(); Should add this assertion onces // it becomes available in compile-testing } @Test public void generatedFile_shouldHandleInnerClassCollisions() { // Because the Generated annotation has a retention of "source", it can't // be tested by a unit test - must run a source-level test. ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowOuterDummy.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowUniqueDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_InnerClassCollision.java")); } @Test public void generatedFile_shouldSkipNonPublicClasses() { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowPrivate.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowOuterDummy2.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_HiddenClasses.java")); } @Test public void generatedFile_shouldHandleAnythingShadows() { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowAnything.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_Anything.java")); } @Test public void generatedFile_shouldHandleClassNameOnlyShadows() { ASSERT.about(javaSources()) .that(ImmutableList.of( SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_ClassNameOnly.java")); } @Test public void generatedFile_shouldNotGenerateShadowOfMethodsForExcludedClasses() { ASSERT.about(javaSources()) .that(ImmutableList.of( SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowExcludedFromAndroidSdk.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_NoExcludedTypes.java")); } @Test public void generatedFile_shouldUseSpecifiedPackage() throws IOException { StringBuffer expected = new StringBuffer(); BufferedReader reader = new BufferedReader(new InputStreamReader(RobolectricProcessorTest.class.getClassLoader().getResourceAsStream("org/robolectric/Robolectric_ClassNameOnly.java"))); String line; while ((line = reader.readLine()) != null) { expected.append(line).append("\n"); } line = expected.toString(); line = line.replace("package org.robolectric", "package my.test.pkg"); Map<String,String> opts = new HashMap<>(); opts.put(PACKAGE_OPT, "my.test.pkg"); ASSERT.about(javaSources()) .that(ImmutableList.of( SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(opts)) .compilesWithoutError() .and() .generatesSources(forSourceString("Shadows", line)); } @Test public void shouldGenerateMetaInfServicesFile() { ASSERT.about(javaSources()) .that(ImmutableList.of( SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowClassNameOnly.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesFiles(forResource("META-INF/services/org.robolectric.internal.ShadowProvider")); } @Test public void shouldGracefullyHandleUnrecognisedAnnotation() { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/TestWithUnrecognizedAnnotation.java"))) .processedWith(new RobolectricProcessor()) .compilesWithoutError(); } @Test public void shouldGracefullyHandleNoAnythingClass_withNoRealObject() { ASSERT.about(javaSource()) .that(forResource("org/robolectric/annotation/processing/shadows/ShadowAnything.java")) .processedWith(new RobolectricProcessor()) .failsToCompile(); } @Test public void shouldGracefullyHandleNoAnythingClass_withFoundOnImplementsAnnotation() { ASSERT.about(javaSources()) .that(ImmutableList.of( SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowRealObjectWithCorrectAnything.java"))) .processedWith(new RobolectricProcessor()) .failsToCompile(); } @Test public void shouldGenerateGenericShadowOf() { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowParameterizedDummy.java"))) .processedWith(new RobolectricProcessor(DEFAULT_OPTS)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_Parameterized.java")); } @Test public void generatedShadowProvider_canConfigureInstrumentingPackages() { Map<String, String> options = new HashMap<>(); options.put(PACKAGE_OPT, "org.robolectric"); options.put(SHOULD_INSTRUMENT_PKG_OPT, "false"); ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, SHADOW_PROVIDER_SOURCE, SHADOW_EXTRACTOR_SOURCE, forResource("org/robolectric/annotation/processing/shadows/ShadowAnything.java"), forResource("org/robolectric/annotation/processing/shadows/ShadowDummy.java"))) .processedWith(new RobolectricProcessor(options)) .compilesWithoutError() .and() .generatesSources(forResource("org/robolectric/Robolectric_EmptyProvidedPackageNames.java")); } @Test public void shouldGenerateJavadocJson() throws Exception { ASSERT.about(javaSources()) .that(ImmutableList.of( ROBO_SOURCE, forResource("org/robolectric/annotation/processing/shadows/DocumentedObjectShadow.java"))) .processedWith(new RobolectricProcessor()) .compilesWithoutError(); JsonParser jsonParser = new JsonParser(); String jsonFile = "build/docs/json/org.robolectric.Robolectric.DocumentedObject.json"; JsonElement json = jsonParser.parse(new BufferedReader(new FileReader(jsonFile))); assertThat(((JsonObject) json).get("documentation").getAsString()) .isEqualTo("Robolectric Javadoc goes here!\n"); // must list imported classes, including inner classes... assertThat(((JsonObject) json).get("imports").getAsJsonArray()) .containsExactly( new JsonPrimitive("org.robolectric.Robolectric"), new JsonPrimitive("org.robolectric.annotation.Implementation"), new JsonPrimitive("org.robolectric.annotation.Implements"), new JsonPrimitive("org.robolectric.annotation.Resetter"), new JsonPrimitive("java.util.Map"), new JsonPrimitive("org.robolectric.annotation.processing.shadows.DocumentedObjectShadow.SomeEnum") ); } }