Skip to content
This repository was archived by the owner on Oct 17, 2023. It is now read-only.

Commit 7b8898e

Browse files
EgorandJakeWharton
authored andcommitted
Sort injected names in generated module code
1 parent d1bbb5e commit 7b8898e

File tree

2 files changed

+139
-1
lines changed

2 files changed

+139
-1
lines changed

inflation-inject-processor/src/main/java/app/cash/inject/inflation/processor/InflationInjectionModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ data class InflationInjectionModule(
4242
.addMethod(MethodSpec.constructorBuilder()
4343
.addModifiers(PRIVATE)
4444
.build())
45-
.applyEach(injectedNames) { injectedName ->
45+
.applyEach(injectedNames.sorted()) { injectedName ->
4646
addMethod(MethodSpec.methodBuilder(injectedName.bindMethodName())
4747
.addAnnotation(BINDS)
4848
.addAnnotation(INTO_MAP)

inflation-inject-processor/src/test/java/app/cash/inject/inflation/processor/InflationInjectProcessorTest.kt

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1061,5 +1061,143 @@ class InflationInjectProcessorTest {
10611061
@Test fun multipleModulesAcrossRoundsFails() {
10621062
}
10631063

1064+
@Test fun multipleViewsStableOrder() {
1065+
val inputViewA = JavaFileObjects.forSourceString("test.TestViewA", """
1066+
package test;
1067+
1068+
import android.content.Context;
1069+
import android.util.AttributeSet;
1070+
import android.view.View;
1071+
import app.cash.inject.inflation.Inflated;
1072+
import app.cash.inject.inflation.InflationInject;
1073+
1074+
class TestViewA extends View {
1075+
@InflationInject
1076+
TestViewA(@Inflated Context context, @Inflated AttributeSet attrs, Long foo) {
1077+
super(context, attrs);
1078+
}
1079+
}
1080+
""")
1081+
val inputViewB = JavaFileObjects.forSourceString("test.TestViewA", """
1082+
package test;
1083+
1084+
import android.content.Context;
1085+
import android.util.AttributeSet;
1086+
import android.view.View;
1087+
import app.cash.inject.inflation.Inflated;
1088+
import app.cash.inject.inflation.InflationInject;
1089+
1090+
class TestViewB extends View {
1091+
@InflationInject
1092+
TestViewB(@Inflated Context context, @Inflated AttributeSet attrs, Long foo) {
1093+
super(context, attrs);
1094+
}
1095+
}
1096+
""")
1097+
val inputModule = JavaFileObjects.forSourceString("test.TestModule", """
1098+
package test;
1099+
1100+
import app.cash.inject.inflation.InflationModule;
1101+
import dagger.Module;
1102+
1103+
@InflationModule
1104+
@Module(includes = InflationInject_TestModule.class)
1105+
abstract class TestModule {}
1106+
""")
1107+
1108+
val expectedFactoryA = JavaFileObjects.forSourceString("test.TestViewA_InflationFactory", """
1109+
package test;
1110+
1111+
import android.content.Context;
1112+
import android.util.AttributeSet;
1113+
import android.view.View;
1114+
import app.cash.inject.inflation.ViewFactory;
1115+
import java.lang.Long;
1116+
import java.lang.Override;
1117+
import $GENERATED_TYPE;
1118+
import javax.inject.Inject;
1119+
import javax.inject.Provider;
1120+
1121+
$GENERATED_ANNOTATION
1122+
public final class TestViewA_InflationFactory implements ViewFactory {
1123+
private final Provider<Long> foo;
1124+
1125+
@Inject public TestViewA_InflationFactory(Provider<Long> foo) {
1126+
this.foo = foo;
1127+
}
1128+
1129+
@Override public View create(Context context, AttributeSet attrs) {
1130+
return new TestViewA(context, attrs, foo.get());
1131+
}
1132+
}
1133+
""")
1134+
val expectedFactoryB = JavaFileObjects.forSourceString("test.TestViewB_InflationFactory", """
1135+
package test;
1136+
1137+
import android.content.Context;
1138+
import android.util.AttributeSet;
1139+
import android.view.View;
1140+
import app.cash.inject.inflation.ViewFactory;
1141+
import java.lang.Long;
1142+
import java.lang.Override;
1143+
import $GENERATED_TYPE;
1144+
import javax.inject.Inject;
1145+
import javax.inject.Provider;
1146+
1147+
$GENERATED_ANNOTATION
1148+
public final class TestViewB_InflationFactory implements ViewFactory {
1149+
private final Provider<Long> foo;
1150+
1151+
@Inject public TestViewB_InflationFactory(Provider<Long> foo) {
1152+
this.foo = foo;
1153+
}
1154+
1155+
@Override public View create(Context context, AttributeSet attrs) {
1156+
return new TestViewB(context, attrs, foo.get());
1157+
}
1158+
}
1159+
""")
1160+
val expectedModule = JavaFileObjects.forSourceString("test.InflationModule_TestModule", """
1161+
package test;
1162+
1163+
import app.cash.inject.inflation.ViewFactory;
1164+
import dagger.Binds;
1165+
import dagger.Module;
1166+
import dagger.multibindings.IntoMap;
1167+
import dagger.multibindings.StringKey;
1168+
import $GENERATED_TYPE;
1169+
1170+
@Module
1171+
$GENERATED_ANNOTATION
1172+
abstract class InflationInject_TestModule {
1173+
private InflationInject_TestModule() {}
1174+
1175+
@Binds
1176+
@IntoMap
1177+
@StringKey("test.TestViewA")
1178+
abstract ViewFactory bind_test_TestViewA(TestViewA_InflationFactory factory);
1179+
1180+
@Binds
1181+
@IntoMap
1182+
@StringKey("test.TestViewB")
1183+
abstract ViewFactory bind_test_TestViewB(TestViewB_InflationFactory factory);
1184+
}
1185+
""")
1186+
1187+
assertAbout(javaSources())
1188+
.that(listOf(inputViewA, inputViewB, inputModule))
1189+
.processedWith(InflationInjectProcessor())
1190+
.compilesWithoutError()
1191+
.and()
1192+
.generatesSources(expectedFactoryA, expectedFactoryB, expectedModule)
1193+
1194+
assertAbout(javaSources())
1195+
.that(listOf(inputViewB, inputViewA, inputModule)) // Inputs passed in reverse order.
1196+
.processedWith(InflationInjectProcessor())
1197+
.compilesWithoutError()
1198+
.and()
1199+
.generatesSources(expectedFactoryA, expectedFactoryB, expectedModule)
1200+
}
1201+
10641202
// TODO module and no inflation injects (what do we do here? bind empty map? fail?)
10651203
}

0 commit comments

Comments
 (0)