1 /* <lambda>null2 * Copyright (C) 2023 The Dagger Authors. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package dagger.hilt.android.processor.internal.viewmodel 18 19 import androidx.room.compiler.processing.ExperimentalProcessingApi 20 import androidx.room.compiler.processing.util.Source 21 import com.google.common.collect.ImmutableList 22 import com.google.common.collect.ImmutableMap 23 import dagger.hilt.android.testing.compile.HiltCompilerTests 24 import dagger.internal.codegen.ComponentProcessor 25 import dagger.internal.codegen.KspComponentProcessor 26 import dagger.testing.compile.CompilerTests.* 27 import org.junit.Test 28 import org.junit.runner.RunWith 29 import org.junit.runners.JUnit4 30 31 @ExperimentalProcessingApi 32 @RunWith(JUnit4::class) 33 class ViewModelValidationPluginWithAssistedInjectTest { 34 35 private fun testCompiler(vararg sources: Source): HiltCompilerTests.HiltCompiler = 36 HiltCompilerTests.hiltCompiler(ImmutableList.copyOf(sources)) 37 .withAdditionalJavacProcessors( 38 ComponentProcessor.withTestPlugins(ViewModelValidationPlugin()), 39 ViewModelProcessor() 40 ) 41 .withAdditionalKspProcessors( 42 KspComponentProcessor.Provider.withTestPlugins(ViewModelValidationPlugin()), 43 KspViewModelProcessor.Provider() 44 ) 45 .withProcessorOptions(ImmutableMap.of("dagger.hilt.enableAssistedInjectViewModels", "true")) 46 47 private val hiltAndroidApp = 48 """ 49 package dagger.hilt.android.test; 50 51 import android.app.Application; 52 import dagger.hilt.android.HiltAndroidApp; 53 54 @HiltAndroidApp(Application.class) 55 public class TestApplication extends Hilt_TestApplication {} 56 """ 57 .toJFO("dagger.hilt.android.test.TestApplication") 58 59 @Test 60 fun injectViewModelAssistedFactoryProhibited() { 61 val hiltActivity = 62 """ 63 package dagger.hilt.android.test; 64 65 import androidx.fragment.app.FragmentActivity; 66 import dagger.hilt.android.AndroidEntryPoint; 67 import javax.inject.Inject; 68 69 @AndroidEntryPoint(FragmentActivity.class) 70 public class TestActivity extends Hilt_TestActivity { 71 @Inject Foo foo; 72 } 73 """ 74 .toJFO("dagger.hilt.android.test.TestActivity") 75 val hiltViewModel = 76 """ 77 package dagger.hilt.android.test; 78 79 import androidx.lifecycle.ViewModel; 80 import dagger.assisted.Assisted; 81 import dagger.assisted.AssistedFactory; 82 import dagger.assisted.AssistedInject; 83 import dagger.hilt.android.lifecycle.HiltViewModel; 84 import javax.inject.Inject; 85 86 @HiltViewModel(assistedFactory = MyViewModel.Factory.class) 87 class MyViewModel extends ViewModel { 88 @AssistedInject MyViewModel(@Assisted String s) { } 89 @AssistedFactory interface Factory { 90 MyViewModel create(String s); 91 } 92 } 93 """ 94 .toJFO("dagger.hilt.android.test.MyViewModel") 95 val foo = 96 """ 97 package dagger.hilt.android.test; 98 99 import javax.inject.Inject; 100 101 final class Foo { 102 @Inject Foo(MyViewModel.Factory factory) {} 103 } 104 """ 105 .toJFO("dagger.hilt.android.test.Foo") 106 107 testCompiler(foo, hiltViewModel, hiltAndroidApp, hiltActivity).compile { subject -> 108 subject.compilationDidFail() 109 subject.hasErrorCount(1) 110 subject.hasErrorContaining( 111 "Injection of an assisted factory for Hilt ViewModel is prohibited since it can not be " + 112 "used to create a ViewModel instance correctly.\n" + 113 "Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.\n" + 114 "Injected factory: dagger.hilt.android.test.MyViewModel.Factory" 115 ) 116 } 117 } 118 119 @Test 120 fun fieldInjectViewModelAssistedFactoryProhibited() { 121 val hiltActivity = 122 """ 123 package dagger.hilt.android.test; 124 125 import androidx.fragment.app.FragmentActivity; 126 import dagger.hilt.android.AndroidEntryPoint; 127 import javax.inject.Inject; 128 129 @AndroidEntryPoint(FragmentActivity.class) 130 public class TestActivity extends Hilt_TestActivity { 131 @Inject MyViewModel.Factory factory; 132 } 133 """ 134 .toJFO("dagger.hilt.android.test.TestActivity") 135 val hiltViewModel = 136 """ 137 package dagger.hilt.android.test; 138 139 import androidx.lifecycle.ViewModel; 140 import dagger.assisted.Assisted; 141 import dagger.assisted.AssistedFactory; 142 import dagger.assisted.AssistedInject; 143 import dagger.hilt.android.lifecycle.HiltViewModel; 144 import javax.inject.Inject; 145 146 @HiltViewModel(assistedFactory = MyViewModel.Factory.class) 147 class MyViewModel extends ViewModel { 148 @AssistedInject MyViewModel(@Assisted String s) { } 149 @AssistedFactory interface Factory { 150 MyViewModel create(String s); 151 } 152 } 153 """ 154 .toJFO("dagger.hilt.android.test.MyViewModel") 155 156 testCompiler(hiltViewModel, hiltAndroidApp, hiltActivity).compile { subject -> 157 subject.compilationDidFail() 158 subject.hasErrorCount(1) 159 subject.hasErrorContaining( 160 "Injection of an assisted factory for Hilt ViewModel is prohibited since it can not be " + 161 "used to create a ViewModel instance correctly.\n" + 162 "Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.\n" + 163 "Injected factory: dagger.hilt.android.test.MyViewModel.Factory" 164 ) 165 } 166 } 167 168 @Test 169 fun injectGenericViewModelAssistedFactoryProhibited() { 170 val hiltActivity = 171 """ 172 package dagger.hilt.android.test; 173 174 import androidx.fragment.app.FragmentActivity; 175 import dagger.hilt.android.AndroidEntryPoint; 176 import javax.inject.Inject; 177 178 @AndroidEntryPoint(FragmentActivity.class) 179 public class TestActivity extends Hilt_TestActivity { 180 @Inject MyViewModel.Factory factory; 181 } 182 """ 183 .toJFO("dagger.hilt.android.test.TestActivity") 184 val hiltViewModel = 185 """ 186 package dagger.hilt.android.test; 187 188 import androidx.lifecycle.ViewModel; 189 import dagger.assisted.Assisted; 190 import dagger.assisted.AssistedFactory; 191 import dagger.assisted.AssistedInject; 192 import dagger.hilt.android.lifecycle.HiltViewModel; 193 import javax.inject.Inject; 194 195 @HiltViewModel(assistedFactory = MyViewModel.Factory.class) 196 class MyViewModel extends ViewModel { 197 @AssistedInject MyViewModel(@Assisted String s) { } 198 interface SingleAssistedFactory<A, T> { 199 T create(A a); 200 } 201 @AssistedFactory interface Factory extends SingleAssistedFactory<String, MyViewModel> {} 202 } 203 """ 204 .toJFO("dagger.hilt.android.test.MyViewModel") 205 206 testCompiler(hiltViewModel, hiltAndroidApp, hiltActivity).compile { subject -> 207 subject.compilationDidFail() 208 subject.hasErrorCount(1) 209 subject.hasErrorContaining( 210 "Injection of an assisted factory for Hilt ViewModel is prohibited since it can not be " + 211 "used to create a ViewModel instance correctly.\n" + 212 "Access the ViewModel via the Android APIs (e.g. ViewModelProvider) instead.\n" + 213 "Injected factory: dagger.hilt.android.test.MyViewModel.Factory" 214 ) 215 } 216 } 217 } 218