@Before public void setup() { Messager messager = new TestMessager(); elements = rule.getElements(); processingEnvironment = new TestProcessingEnvironment(messager, elements, rule.getTypes()); parcelable = JavaFileObjects.forSourceString( "android.os.Parcelable", "" + "package android.os;\n" + "public interface Parcelable {\n" + "public interface Creator<T> {\n" + " public T createFromParcel(Parcel source);\n" + " public T[] newArray(int size);\n" + "}" + "int describeContents();\n" + "void writeToParcel(Parcel in, int flags);\n" + "}\n"); parcel = JavaFileObjects.forSourceString( "android.os.Parcel", "" + "package android.os;\n" + "public interface Parcel {\n" + "Object readValue(ClassLoader cl);\n" + "void writeValue(Object o);\n" + "}"); }
@Test public void factoryMethod_nonModuleParameter() { JavaFileObject componentFile = JavaFileObjects.forSourceLines( "test.TestComponent", "package test;", "", "import dagger.Component;", "", "@Component", "interface TestComponent {", " ChildComponent newChildComponent(String someRandomString);", "}"); JavaFileObject childComponentFile = JavaFileObjects.forSourceLines( "test.ChildComponent", "package test;", "", "import dagger.Subcomponent;", "", "@Subcomponent", "interface ChildComponent {}"); assertAbout(javaSources()) .that(ImmutableList.of(componentFile, childComponentFile)) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining( "Subcomponent factory methods may only accept modules, but java.lang.String is not.") .in(componentFile) .onLine(7) .atColumn(43); }
@Test public void testTable() { JavaFileObject source = JavaFileObjects.forSourceString( "test.Test", Joiner.on('\n') .join( "package test;", "import Table;", "import Key;", "@Table", "public class Test {", " @Key long id;", " String name;", "}")); JavaFileObject expectedSource = JavaFileObjects.forSourceString( "test/Test$$ViewBinder", Joiner.on('\n') .join( "// Generated code from Cying-ORM. Do not modify!", "package test;", "import android.content.ContentValues;", "import android.database.Cursor;", "import BaseDao;", "public class Test$$Dao extends BaseDao<Test> {", " private static String SQL=\"CREATE TABLE test (id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT);\"", " static {", " saveSQL(SQL);", " }", " @Override protected Test cursorToEntity(Cursor cursor) {", " Test entity=new Test();", " entity.id=cursor.getLong(cursor.getColumnIndex(\"id\"));", " entity.name=cursor.getString(cursor.getColumnIndex(\"name\"));", " return entity;", " }", " @Override protected ContentValues entityToValues(Test entity) {", " ContentValues values=new ContentValues();", " values.put(\"name\",entity.name)", " return values;", " }", " @Override public String getTableName() {", " return \"test\";", " }", " @Override public String getTableSQL() { return SQL; }", " @Override public String getIdentityName() {", " return \"id\";", " }", " @Override public long getIdentity(Test entity) {", " return entity.id;", " }", "}")); Truth.assertAbout(javaSource()) .that(source) .processedWith(new ORMProcessor()) .compilesWithoutError() .and() .generatesSources(expectedSource); }
@Test public void methodWithMultipleIds() { JavaFileObject source = JavaFileObjects.forSourceString( "test.Test", Joiner.on('\n') .join( "package test;", "import android.app.Activity;", "import android.view.View;", "import butterknife.OnClick;", "public class Test extends Activity {", " @OnClick({1, 2, 3}) void click() {}", "}")); JavaFileObject expectedSource = JavaFileObjects.forSourceString( "test/Test$$ViewInjector", Joiner.on('\n') .join( "package test;", "import android.view.View;", "import butterknife.ButterKnife.Finder;", "import butterknife.ButterKnife.Injector;", "public class Test$$ViewInjector<T extends test.Test> implements Injector<T> {", " @Override public void inject(final Finder finder, final T target, Object source) {", " View view;", " view = finder.findRequiredView(source, 1, \"method 'click'\");", " view.setOnClickListener(new butterknife.internal.DebouncingOnClickListener() {", " @Override public void doClick(android.view.View p0) {", " target.click();", " }", " });", " view = finder.findRequiredView(source, 2, \"method 'click'\");", " view.setOnClickListener(new butterknife.internal.DebouncingOnClickListener() {", " @Override public void doClick(android.view.View p0) {", " target.click();", " }", " });", " view = finder.findRequiredView(source, 3, \"method 'click'\");", " view.setOnClickListener(new butterknife.internal.DebouncingOnClickListener() {", " @Override public void doClick(android.view.View p0) {", " target.click();", " }", " });", " }", " @Override public void reset(T target) {", " }", "}")); ASSERT .about(javaSource()) .that(source) .processedWith(butterknifeProcessors()) .compilesWithoutError() .and() .generatesSources(expectedSource); }
@Test public void publicClass() { assert_() .about(javaSource()) .that(JavaFileObjects.forResource("good/PublicClass.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources(JavaFileObjects.forResource("expected/PublicClassFactory.java")); }
@Test public void constructorAnnotated() { ASSERT .about(javaSource()) .that(JavaFileObjects.forResource("good/ConstructorAnnotated.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources(JavaFileObjects.forResource("expected/ConstructorAnnotatedFactory.java")); }
@Test public void simpleClassCustomName() { assert_() .about(javaSource()) .that(JavaFileObjects.forResource("good/SimpleClassCustomName.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources(JavaFileObjects.forResource("expected/CustomNamedFactory.java")); }
@Test public void factoryMethod_missingModulesWithParameters() { JavaFileObject componentFile = JavaFileObjects.forSourceLines( "test.TestComponent", "package test;", "", "import dagger.Component;", "", "@Component", "interface TestComponent {", " ChildComponent newChildComponent();", "}"); JavaFileObject childComponentFile = JavaFileObjects.forSourceLines( "test.ChildComponent", "package test;", "", "import dagger.Subcomponent;", "", "@Subcomponent(modules = ModuleWithParameters.class)", "interface ChildComponent {", " Object object();", "}"); JavaFileObject moduleFile = JavaFileObjects.forSourceLines( "test.ModuleWithParameters", "package test;", "", "import dagger.Module;", "import dagger.Provides;", "", "@Module", "final class ModuleWithParameters {", " private final Object object;", "", " ModuleWithParameters(Object object) {", " this.object = object;", " }", "", " @Provides Object object() {", " return object;", " }", "}"); assertAbout(javaSources()) .that(ImmutableList.of(componentFile, childComponentFile, moduleFile)) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining( "test.ChildComponent requires modules which have no visible default constructors. " + "Add the following modules as parameters to this method: " + "test.ModuleWithParameters") .in(componentFile) .onLine(7); }
@Test public void mixedDepsImplementingInterfaces() { assert_() .about(javaSource()) .that(JavaFileObjects.forResource("good/MixedDepsImplementingInterfaces.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources( JavaFileObjects.forResource("expected/MixedDepsImplementingInterfacesFactory.java")); }
@Test public void simpleClassPassedDeps() { ASSERT .about(javaSource()) .that(JavaFileObjects.forResource("good/SimpleClassPassedDeps.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources( JavaFileObjects.forResource("expected/SimpleClassPassedDepsFactory.java")); }
@Test public void factoryExtendingAbstractClass() { ASSERT .about(javaSource()) .that(JavaFileObjects.forResource("good/FactoryExtendingAbstractClass.java")) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources( JavaFileObjects.forResource("expected/FactoryExtendingAbstractClassFactory.java")); }
@Test public void shouldCompileWithoutError() throws Exception { JavaFileObject source = JavaFileObjects.forSourceString( "LocalStorage", Joiner.on('\n') .join( "package test;", "import de.ad.sharp.api.SharedPreference;", "import java.util.Date;", "@SharedPreference public interface LocalStorage {", " int getIntPreference();", " void setIntPreference(int value);", " long getLongPreference();", " void setLongPreference(long value);", " float getFloatPreference();", " void setFloatPreference(float value);", " boolean isBooleanPreference();", " void setBooleanPreference(boolean value);", " String getStringPreference();", " void setStringPreference(String value);", " Date getDatePreference();", " void setDatePreference(Date value);", "void reset();", "}")); JavaFileObject expectedSource = JavaFileObjects.forSourceString( "LocalStorageImpl", Joiner.on('\n') .join( "package test;", "import de.ad.sharp.api.SharedPreference;", "@SharedPreference public interface LocalStorage {", " int getIntPreference();", " void setIntPreference(int value);", " long getLongPreference();", " void setLongPreference(long value);", " float getFloatPreference();", " void setFloatPreference(float value);", " boolean getBooleanPreference();", " void setBooleanPreference(boolean value);", " String getStringPreference();", " void setStringPreference(String value);", "}")); assertAbout(javaSource()) .that(source) .processedWith(new SharedPreferenceProcessor()) .compilesWithoutError(); // http://stackoverflow.com/questions/32394726/assertionerror-when-unit-testing-an-annotation-processor-with-compile-testing // .and().generatesSources(expectedSource); }
@Test public void simpleClassMixedDeps() { assert_() .about(javaSources()) .that( ImmutableSet.of( JavaFileObjects.forResource("good/SimpleClassMixedDeps.java"), JavaFileObjects.forResource("support/AQualifier.java"))) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources(JavaFileObjects.forResource("expected/SimpleClassMixedDepsFactory.java")); }
@Test public void factoryImplementingGenericInterfaceExtension() { JavaFileObject file = JavaFileObjects.forResource("good/FactoryImplementingGenericInterfaceExtension.java"); assert_() .about(javaSource()) .that(file) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError() .and() .generatesSources( JavaFileObjects.forResource( "expected/FactoryImplementingGenericInterfaceExtension.java")); }
@Test public void testPrivateModelValues() { final String content = "" + "package com.yella;\n" + "import com.ngandroid.lib.annotations.NgModel;\n" + "import com.ngandroid.lib.annotations.NgScope;\n\n" + "@NgScope \n" + "class PrivateScope {\n" + " @NgModel\n" + " Model model;" + "}\n" + "class Model {\n" + " private void setX(int x){\n" + " }\n" + " private int getX(){\n" + " return 0;\n" + " }\n" + "}"; JavaFileObject fileObject = JavaFileObjects.forSourceString("com.yella.PrivateScope", content); ASSERT .about(javaSource()) .that(fileObject) .processedWith( Collections.singletonList( new NgProcessor("ng-processor/src/test/resources/emptylayout"))) .failsToCompile() .withErrorContaining("Unable to access field") .in(fileObject) .onLine(10); }
@Test public void rawComparableTypeMixedTypes() { JavaFileObject file = JavaFileObjects.forSourceLines( "test.MyTest", "package test;", "import static com.google.common.truth.Truth.assertThat;", "class MyTest {", " public void testFoo() {", " assertThat(new RawComparableType(3)).isLessThan(\"kak\");", " }", " private static final class RawComparableType implements Comparable {", " private final int wrapped;", " private RawComparableType(int toWrap) {", " this.wrapped = toWrap;", " }", " @Override public int compareTo(Object other) {", " return wrapped - ((RawComparableType) other).wrapped;", " }", " }", "}"); assert_() .about(javaSource()) .that(file) .failsToCompile() .withErrorContaining( "reason: actual argument java.lang.String cannot be converted to " + "test.MyTest.RawComparableType by method invocation conversion") .in(file) .onLine(5); }
@Test public void testPrivateUsedMethod() { final String content = "" + "package com.yella;\n" + "import com.ngandroid.lib.annotations.NgModel;\n" + "import com.ngandroid.lib.annotations.NgScope;\n\n" + "@NgScope \n" + "class PrivateScope {\n" + " private void method(){\n" + " }\n" + "}"; JavaFileObject fileObject = JavaFileObjects.forSourceString("com.yella.PrivateScope", content); ASSERT .about(javaSource()) .that(fileObject) .processedWith( Collections.singletonList( new NgProcessor("ng-processor/src/test/resources/test_private_method"))) .failsToCompile() .withErrorContaining("is not accessible") .in(fileObject) .onLine(7); }
@Test public void failsIfStatic() { JavaFileObject source = JavaFileObjects.forSourceString( "test.Test", Joiner.on('\n') .join( "package test;", "import android.app.Activity;", "import butterknife.OnClick;", "public class Test extends Activity {", " @OnClick(1)", " public static void doStuff() {", " }", "}")); ASSERT .about(javaSource()) .that(source) .processedWith(butterknifeProcessors()) .failsToCompile() .withErrorContaining("@OnClick methods must not be private or static. (test.Test.doStuff)") .in(source) .onLine(6); }
@Test public void failsIfMoreThanOneParameter() { JavaFileObject source = JavaFileObjects.forSourceString( "test.Test", Joiner.on('\n') .join( "package test;", "import android.app.Activity;", "import android.view.View;", "import butterknife.OnClick;", "public class Test extends Activity {", " @OnClick(1)", " public void doStuff(View thing, View otherThing) {", " }", "}")); ASSERT .about(javaSource()) .that(source) .processedWith(butterknifeProcessors()) .failsToCompile() .withErrorContaining( "@OnClick methods can have at most 1 parameter(s). (test.Test.doStuff)") .in(source) .onLine(7); }
@Test public void failsIfHasDuplicateIds() { JavaFileObject source = JavaFileObjects.forSourceString( "test.Test", Joiner.on('\n') .join( "package test;", "import android.app.Activity;", "import butterknife.OnClick;", "public class Test extends Activity {", " @OnClick({1, 2, 3, 1})", " void doStuff() {", " }", "}")); ASSERT .about(javaSource()) .that(source) .processedWith(butterknifeProcessors()) .failsToCompile() .withErrorContaining( "@OnClick annotation for method contains duplicate ID 1. (test.Test.doStuff)") .in(source) .onLine(6); }
@Test public void missingEmptyConstructor() { JavaFileObject helperClass = JavaFileObjects.forSourceString( "com.example.MyDatabaseHelper", Joiner.on('\n') .join( "package com.example;", "", "import eu.f3rog.ormlite.helper.Helper;", "import eu.f3rog.ormlite.helper.OnUpgrade;", "", "@Helper(", " name = \"my_database.db\",", " tables = {}", ")", "public class MyDatabaseHelper {", "", " public MyDatabaseHelper(int i) { }", "", "}")); Truth.assert_() .about(JavaSourcesSubjectFactory.javaSources()) .that(files(helperClass)) .processedWith(new eu.f3rog.ormlite.helper.compiler.HelperProcessor()) .failsToCompile() .withErrorContaining("must have empty constructor"); }
@Test public void wrong2ndOnUpgradeParam() { JavaFileObject helperClass = JavaFileObjects.forSourceString( "com.example.MyDatabaseHelper", Joiner.on('\n') .join( "package com.example;", "", "import android.database.sqlite.SQLiteDatabase;", "import com.j256.ormlite.support.ConnectionSource;", "import eu.f3rog.ormlite.helper.Helper;", "import eu.f3rog.ormlite.helper.OnUpgrade;", "", "@Helper(", " name = \"my_database.db\",", " tables = {}", ")", "public class MyDatabaseHelper {", "", " @OnUpgrade(to = 1)", " public void up(SQLiteDatabase database, Object o) {}", "", "}")); Truth.assert_() .about(JavaSourcesSubjectFactory.javaSources()) .that(files(helperClass)) .processedWith(new eu.f3rog.ormlite.helper.compiler.HelperProcessor()) .failsToCompile() .withErrorContaining("must have 2nd parameter of type"); }
@Test public void multipleProducesMethodsWithSameName() { JavaFileObject moduleFile = JavaFileObjects.forSourceLines( "test.TestModule", "package test;", "", "import dagger.producers.ProducerModule;", "import dagger.producers.Produces;", "", "@ProducerModule", "final class TestModule {", " @Produces Object produce(int i) {", " return i;", " }", "", " @Produces String produce() {", " return \"\";", " }", "}"); String errorMessage = String.format(BINDING_METHOD_WITH_SAME_NAME, "Produces"); assertAbout(javaSource()) .that(moduleFile) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining(errorMessage) .in(moduleFile) .onLine(8) .and() .withErrorContaining(errorMessage) .in(moduleFile) .onLine(12); }
@Test public void shouldCompileDefaultSharedPreferenceWithoutError() throws Exception { JavaFileObject source = JavaFileObjects.forSourceString( "LocalStorage", Joiner.on('\n') .join( "package test;", "import de.ad.sharp.api.DefaultSharedPreference;", "@DefaultSharedPreference public interface LocalStorage {", " int getIntPreference();", " void setIntPreference(int value);", " long getLongPreference();", " void setLongPreference(long value);", " float getFloatPreference();", " void setFloatPreference(float value);", " boolean isBooleanPreference();", " void setBooleanPreference(boolean value);", " String getStringPreference();", " void setStringPreference(String value);", "void reset();", "}")); assertAbout(javaSource()) .that(source) .processedWith(new SharedPreferenceProcessor()) .compilesWithoutError(); }
private JavaFileObject classFile(String packageName, String className) { return JavaFileObjects.forSourceString( String.format("%s.%s", packageName, className), Joiner.on('\n') .join( String.format("package %s;", packageName), String.format("public class %s {}", className))); }
@Test public void missingBinding() { JavaFileObject moduleFile = JavaFileObjects.forSourceLines( "test.TestModule", "package test;", "", "import dagger.Module;", "import dagger.Provides;", "", "@Module", "final class TestModule {", " @Provides String provideString(int i) {", " return Integer.toString(i);", " }", "}"); JavaFileObject componentFile = JavaFileObjects.forSourceLines( "test.TestComponent", "package test;", "", "import dagger.Component;", "", "@Component", "interface TestComponent {", " ChildComponent newChildComponent();", "}"); JavaFileObject childComponentFile = JavaFileObjects.forSourceLines( "test.ChildComponent", "package test;", "", "import dagger.Subcomponent;", "", "@Subcomponent(modules = TestModule.class)", "interface ChildComponent {", " String getString();", "}"); assertAbout(javaSources()) .that(ImmutableList.of(moduleFile, componentFile, childComponentFile)) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining( "java.lang.Integer cannot be provided without an @Inject constructor or from an " + "@Provides-annotated method"); }
@Test public void scopeMismatch() { JavaFileObject componentFile = JavaFileObjects.forSourceLines( "test.ParentComponent", "package test;", "", "import dagger.Component;", "import javax.inject.Singleton;", "", "@Component", "@Singleton", "interface ParentComponent {", " ChildComponent childComponent();", "}"); JavaFileObject subcomponentFile = JavaFileObjects.forSourceLines( "test.ChildComponent", "package test;", "", "import dagger.Subcomponent;", "", "@Subcomponent(modules = ChildModule.class)", "interface ChildComponent {", " Object getObject();", "}"); JavaFileObject moduleFile = JavaFileObjects.forSourceLines( "test.ChildModule", "package test;", "", "import dagger.Module;", "import dagger.Provides;", "import javax.inject.Singleton;", "", "@Module", "final class ChildModule {", " @Provides @Singleton Object provideObject() { return null; }", "}"); assertAbout(javaSources()) .that(ImmutableList.of(componentFile, subcomponentFile, moduleFile)) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining("@Singleton"); }
public SingleClassSubject(FailureStrategy failureStrategy, String subject) { super(failureStrategy, subject); source = JavaFileObjects.forResource(Utils.toResourcePath(subject)); tester = ASSERT .about(javaSources()) .that(ImmutableList.of(source, Utils.ROBO_SOURCE, Utils.SHADOW_EXTRACTOR_SOURCE)) .processedWith(new RobolectricProcessor()); }
@Test public void factoryMethod_duplicateParameter() { JavaFileObject moduleFile = JavaFileObjects.forSourceLines( "test.TestModule", "package test;", "", "import dagger.Module;", "", "@Module", "final class TestModule {}"); JavaFileObject componentFile = JavaFileObjects.forSourceLines( "test.TestComponent", "package test;", "", "import dagger.Component;", "", "@Component", "interface TestComponent {", " ChildComponent newChildComponent(TestModule testModule1, TestModule testModule2);", "}"); JavaFileObject childComponentFile = JavaFileObjects.forSourceLines( "test.ChildComponent", "package test;", "", "import dagger.Subcomponent;", "", "@Subcomponent(modules = TestModule.class)", "interface ChildComponent {}"); assertAbout(javaSources()) .that(ImmutableList.of(moduleFile, componentFile, childComponentFile)) .processedWith(new ComponentProcessor()) .failsToCompile() .withErrorContaining( "A module may only occur once an an argument in a Subcomponent factory method, " + "but test.TestModule was already passed.") .in(componentFile) .onLine(7) .atColumn(71); }
@Test public void factoryExtendingAbstractClass_multipleConstructors() { JavaFileObject file = JavaFileObjects.forResource( "good/FactoryExtendingAbstractClassWithMultipleConstructors.java"); assert_() .about(javaSource()) .that(file) .processedWith(new AutoFactoryProcessor()) .compilesWithoutError(); }