• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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