1 /* 2 * Copyright (C) 2020 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 com.google.testing.compile.CompilationSubject.assertThat 20 import com.google.testing.compile.Compiler 21 import org.junit.Test 22 import org.junit.runner.RunWith 23 import org.junit.runners.JUnit4 24 25 @RunWith(JUnit4::class) 26 class ViewModelGeneratorTest { 27 compilernull28 private fun compiler(): Compiler = Compiler.javac().withProcessors(ViewModelProcessor()) 29 30 @Test 31 fun verifyModule_noArg() { 32 val myViewModel = """ 33 package dagger.hilt.android.test; 34 35 import dagger.hilt.android.lifecycle.HiltViewModel; 36 import androidx.lifecycle.ViewModel; 37 import javax.inject.Inject; 38 39 @HiltViewModel 40 class MyViewModel extends ViewModel { 41 @Inject 42 MyViewModel() { } 43 } 44 """.toJFO("dagger.hilt.android.test.MyViewModel") 45 46 val expected = """ 47 package dagger.hilt.android.test; 48 49 import androidx.lifecycle.ViewModel; 50 import dagger.Binds; 51 import dagger.Module; 52 import dagger.Provides; 53 import dagger.hilt.InstallIn; 54 import dagger.hilt.android.components.ActivityRetainedComponent; 55 import dagger.hilt.android.components.ViewModelComponent; 56 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 57 import dagger.hilt.codegen.OriginatingElement; 58 import dagger.multibindings.IntoMap; 59 import dagger.multibindings.IntoSet; 60 import dagger.multibindings.StringKey; 61 import java.lang.String; 62 import $GENERATED_TYPE 63 64 $GENERATED_ANNOTATION 65 @OriginatingElement( 66 topLevelClass = MyViewModel.class 67 ) 68 public final class MyViewModel_HiltModules { 69 private MyViewModel_HiltModules() { 70 } 71 72 @Module 73 @InstallIn(ViewModelComponent.class) 74 public static abstract class BindsModule { 75 @Binds 76 @IntoMap 77 @StringKey("dagger.hilt.android.test.MyViewModel") 78 @HiltViewModelMap 79 public abstract ViewModel binds(MyViewModel vm); 80 } 81 82 @Module 83 @InstallIn(ActivityRetainedComponent.class) 84 public static final class KeyModule { 85 private KeyModule() { 86 } 87 88 @Provides 89 @IntoSet 90 @HiltViewModelMap.KeySet 91 public static String provide() { 92 return "dagger.hilt.android.test.MyViewModel"; 93 } 94 } 95 } 96 """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule") 97 98 val compilation = compiler() 99 .compile(myViewModel) 100 assertThat(compilation).apply { 101 succeeded() 102 generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules") 103 .hasSourceEquivalentTo(expected) 104 } 105 } 106 107 @Test verifyModule_savedStateOnlyArgnull108 fun verifyModule_savedStateOnlyArg() { 109 val myViewModel = """ 110 package dagger.hilt.android.test; 111 112 import dagger.hilt.android.lifecycle.HiltViewModel; 113 import androidx.lifecycle.ViewModel; 114 import androidx.lifecycle.SavedStateHandle; 115 import javax.inject.Inject; 116 117 @HiltViewModel 118 class MyViewModel extends ViewModel { 119 @Inject 120 MyViewModel(SavedStateHandle savedState) { } 121 } 122 """.toJFO("dagger.hilt.android.test.MyViewModel") 123 124 val expected = """ 125 package dagger.hilt.android.test; 126 127 import androidx.lifecycle.ViewModel; 128 import dagger.Binds; 129 import dagger.Module; 130 import dagger.Provides; 131 import dagger.hilt.InstallIn; 132 import dagger.hilt.android.components.ActivityRetainedComponent; 133 import dagger.hilt.android.components.ViewModelComponent; 134 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 135 import dagger.hilt.codegen.OriginatingElement; 136 import dagger.multibindings.IntoMap; 137 import dagger.multibindings.IntoSet; 138 import dagger.multibindings.StringKey; 139 import java.lang.String; 140 import $GENERATED_TYPE 141 142 $GENERATED_ANNOTATION 143 @OriginatingElement( 144 topLevelClass = MyViewModel.class 145 ) 146 public final class MyViewModel_HiltModules { 147 private MyViewModel_HiltModules() { 148 } 149 150 @Module 151 @InstallIn(ViewModelComponent.class) 152 public static abstract class BindsModule { 153 @Binds 154 @IntoMap 155 @StringKey("dagger.hilt.android.test.MyViewModel") 156 @HiltViewModelMap 157 public abstract ViewModel binds(MyViewModel vm); 158 } 159 160 @Module 161 @InstallIn(ActivityRetainedComponent.class) 162 public static final class KeyModule { 163 private KeyModule() { 164 } 165 166 @Provides 167 @IntoSet 168 @HiltViewModelMap.KeySet 169 public static String provide() { 170 return "dagger.hilt.android.test.MyViewModel"; 171 } 172 } 173 } 174 """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule") 175 176 val compilation = compiler() 177 .compile(myViewModel) 178 assertThat(compilation).apply { 179 succeeded() 180 generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules") 181 .hasSourceEquivalentTo(expected) 182 } 183 } 184 185 @Test verifyModule_mixedArgsnull186 fun verifyModule_mixedArgs() { 187 val foo = """ 188 package dagger.hilt.android.test; 189 190 public class Foo { } 191 """.toJFO("dagger.hilt.android.test.Foo") 192 193 val myViewModel = """ 194 package dagger.hilt.android.test; 195 196 import dagger.hilt.android.lifecycle.HiltViewModel; 197 import androidx.lifecycle.ViewModel; 198 import androidx.lifecycle.SavedStateHandle; 199 import java.lang.String; 200 import javax.inject.Inject; 201 202 @HiltViewModel 203 class MyViewModel extends ViewModel { 204 @Inject 205 MyViewModel(String s, Foo f, SavedStateHandle savedState, long l) { } 206 } 207 """.toJFO("dagger.hilt.android.test.MyViewModel") 208 209 val expected = """ 210 package dagger.hilt.android.test; 211 212 import androidx.lifecycle.ViewModel; 213 import dagger.Binds; 214 import dagger.Module; 215 import dagger.Provides; 216 import dagger.hilt.InstallIn; 217 import dagger.hilt.android.components.ActivityRetainedComponent; 218 import dagger.hilt.android.components.ViewModelComponent; 219 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 220 import dagger.hilt.codegen.OriginatingElement; 221 import dagger.multibindings.IntoMap; 222 import dagger.multibindings.IntoSet; 223 import dagger.multibindings.StringKey; 224 import java.lang.String; 225 import $GENERATED_TYPE 226 227 $GENERATED_ANNOTATION 228 @OriginatingElement( 229 topLevelClass = MyViewModel.class 230 ) 231 public final class MyViewModel_HiltModules { 232 private MyViewModel_HiltModules() { 233 } 234 235 @Module 236 @InstallIn(ViewModelComponent.class) 237 public static abstract class BindsModule { 238 @Binds 239 @IntoMap 240 @StringKey("dagger.hilt.android.test.MyViewModel") 241 @HiltViewModelMap 242 public abstract ViewModel binds(MyViewModel vm); 243 } 244 245 @Module 246 @InstallIn(ActivityRetainedComponent.class) 247 public static final class KeyModule { 248 private KeyModule() { 249 } 250 251 @Provides 252 @IntoSet 253 @HiltViewModelMap.KeySet 254 public static String provide() { 255 return "dagger.hilt.android.test.MyViewModel"; 256 } 257 } 258 } 259 """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModule") 260 261 val compilation = compiler() 262 .compile(foo, myViewModel) 263 assertThat(compilation).apply { 264 succeeded() 265 generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules") 266 .hasSourceEquivalentTo(expected) 267 } 268 } 269 270 @Test verifyModule_mixedAndProviderArgsnull271 fun verifyModule_mixedAndProviderArgs() { 272 val foo = """ 273 package dagger.hilt.android.test; 274 275 public class Foo { } 276 """.toJFO("dagger.hilt.android.test.Foo") 277 278 val myViewModel = """ 279 package dagger.hilt.android.test; 280 281 import dagger.hilt.android.lifecycle.HiltViewModel; 282 import androidx.lifecycle.ViewModel; 283 import androidx.lifecycle.SavedStateHandle; 284 import java.lang.String; 285 import javax.inject.Inject; 286 import javax.inject.Provider; 287 288 @HiltViewModel 289 class MyViewModel extends ViewModel { 290 @Inject 291 MyViewModel(String s, Provider<Foo> f, SavedStateHandle savedState) { } 292 } 293 """.toJFO("dagger.hilt.android.test.MyViewModel") 294 295 val expected = """ 296 package dagger.hilt.android.test; 297 298 import androidx.lifecycle.ViewModel; 299 import dagger.Binds; 300 import dagger.Module; 301 import dagger.Provides; 302 import dagger.hilt.InstallIn; 303 import dagger.hilt.android.components.ActivityRetainedComponent; 304 import dagger.hilt.android.components.ViewModelComponent; 305 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 306 import dagger.hilt.codegen.OriginatingElement; 307 import dagger.multibindings.IntoMap; 308 import dagger.multibindings.IntoSet; 309 import dagger.multibindings.StringKey; 310 import java.lang.String; 311 import $GENERATED_TYPE; 312 313 $GENERATED_ANNOTATION 314 @OriginatingElement( 315 topLevelClass = MyViewModel.class 316 ) 317 public final class MyViewModel_HiltModules { 318 private MyViewModel_HiltModules() { 319 } 320 321 @Module 322 @InstallIn(ViewModelComponent.class) 323 public static abstract class BindsModule { 324 @Binds 325 @IntoMap 326 @StringKey("dagger.hilt.android.test.MyViewModel") 327 @HiltViewModelMap 328 public abstract ViewModel binds(MyViewModel vm); 329 } 330 331 @Module 332 @InstallIn(ActivityRetainedComponent.class) 333 public static final class KeyModule { 334 private KeyModule() { 335 } 336 337 @Provides 338 @IntoSet 339 @HiltViewModelMap.KeySet 340 public static String provide() { 341 return "dagger.hilt.android.test.MyViewModel"; 342 } 343 } 344 } 345 """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModules") 346 347 val compilation = compiler() 348 .compile(foo, myViewModel) 349 assertThat(compilation).apply { 350 succeeded() 351 generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules") 352 .hasSourceEquivalentTo(expected) 353 } 354 } 355 356 @Test verifyModule_qualifiedArgsnull357 fun verifyModule_qualifiedArgs() { 358 val myQualifier = """ 359 package dagger.hilt.android.test; 360 361 import javax.inject.Qualifier; 362 363 @Qualifier 364 public @interface MyQualifier { } 365 """.toJFO("dagger.hilt.android.test.MyQualifier") 366 367 val myViewModel = """ 368 package dagger.hilt.android.test; 369 370 import dagger.hilt.android.lifecycle.HiltViewModel; 371 import androidx.lifecycle.ViewModel; 372 import androidx.lifecycle.SavedStateHandle; 373 import java.lang.Long; 374 import java.lang.String; 375 import javax.inject.Inject; 376 import javax.inject.Named; 377 import javax.inject.Provider; 378 379 @HiltViewModel 380 class MyViewModel extends ViewModel { 381 @Inject 382 MyViewModel(@Named("TheString") String s, @MyQualifier Provider<Long> l, 383 SavedStateHandle savedState) { 384 } 385 } 386 """.toJFO("dagger.hilt.android.test.MyViewModel") 387 388 val expected = """ 389 package dagger.hilt.android.test; 390 391 import androidx.lifecycle.ViewModel; 392 import dagger.Binds; 393 import dagger.Module; 394 import dagger.Provides; 395 import dagger.hilt.InstallIn; 396 import dagger.hilt.android.components.ActivityRetainedComponent; 397 import dagger.hilt.android.components.ViewModelComponent; 398 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 399 import dagger.hilt.codegen.OriginatingElement; 400 import dagger.multibindings.IntoMap; 401 import dagger.multibindings.IntoSet; 402 import dagger.multibindings.StringKey; 403 import java.lang.String; 404 import $GENERATED_TYPE; 405 406 $GENERATED_ANNOTATION 407 @OriginatingElement( 408 topLevelClass = MyViewModel.class 409 ) 410 public final class MyViewModel_HiltModules { 411 private MyViewModel_HiltModules() { 412 } 413 414 @Module 415 @InstallIn(ViewModelComponent.class) 416 public static abstract class BindsModule { 417 @Binds 418 @IntoMap 419 @StringKey("dagger.hilt.android.test.MyViewModel") 420 @HiltViewModelMap 421 public abstract ViewModel binds(MyViewModel vm); 422 } 423 424 @Module 425 @InstallIn(ActivityRetainedComponent.class) 426 public static final class KeyModule { 427 private KeyModule() { 428 } 429 430 @Provides 431 @IntoSet 432 @HiltViewModelMap.KeySet 433 public static String provide() { 434 return "dagger.hilt.android.test.MyViewModel"; 435 } 436 } 437 } 438 """.toJFO("dagger.hilt.android.test.MyViewModel_HiltModules") 439 440 val compilation = compiler() 441 .compile(myQualifier, myViewModel) 442 assertThat(compilation).apply { 443 succeeded() 444 generatedSourceFile("dagger.hilt.android.test.MyViewModel_HiltModules") 445 .hasSourceEquivalentTo(expected) 446 } 447 } 448 449 @Test verifyInnerClassnull450 fun verifyInnerClass() { 451 val viewModel = """ 452 package dagger.hilt.android.test; 453 454 import dagger.hilt.android.lifecycle.HiltViewModel; 455 import androidx.lifecycle.ViewModel; 456 import javax.inject.Inject; 457 458 class Outer { 459 @HiltViewModel 460 static class InnerViewModel extends ViewModel { 461 @Inject 462 InnerViewModel() { } 463 } 464 } 465 """.toJFO("dagger.hilt.android.test.Outer") 466 467 val expectedModule = """ 468 package dagger.hilt.android.test; 469 470 import androidx.lifecycle.ViewModel; 471 import dagger.Binds; 472 import dagger.Module; 473 import dagger.Provides; 474 import dagger.hilt.InstallIn; 475 import dagger.hilt.android.components.ActivityRetainedComponent; 476 import dagger.hilt.android.components.ViewModelComponent; 477 import dagger.hilt.android.internal.lifecycle.HiltViewModelMap; 478 import dagger.hilt.codegen.OriginatingElement; 479 import dagger.multibindings.IntoMap; 480 import dagger.multibindings.IntoSet; 481 import dagger.multibindings.StringKey; 482 import java.lang.String; 483 import $GENERATED_TYPE 484 485 $GENERATED_ANNOTATION 486 @OriginatingElement( 487 topLevelClass = Outer.class 488 ) 489 public final class Outer_InnerViewModel_HiltModules { 490 private Outer_InnerViewModel_HiltModules() { 491 } 492 493 @Module 494 @InstallIn(ViewModelComponent.class) 495 public static abstract class BindsModule { 496 @Binds 497 @IntoMap 498 @StringKey("dagger.hilt.android.test.Outer${'$'}InnerViewModel") 499 @HiltViewModelMap 500 public abstract ViewModel binds(Outer.InnerViewModel vm); 501 } 502 503 @Module 504 @InstallIn(ActivityRetainedComponent.class) 505 public static final class KeyModule { 506 private KeyModule() { 507 } 508 509 @Provides 510 @IntoSet 511 @HiltViewModelMap.KeySet 512 public static String provide() { 513 return "dagger.hilt.android.test.Outer${'$'}InnerViewModel"; 514 } 515 } 516 } 517 """.toJFO("dagger.hilt.android.test.Outer_InnerViewModel_HiltModules") 518 519 val compilation = compiler() 520 .compile(viewModel) 521 assertThat(compilation).apply { 522 succeeded() 523 generatedSourceFile("dagger.hilt.android.test.Outer_InnerViewModel_HiltModules") 524 .hasSourceEquivalentTo(expectedModule) 525 } 526 } 527 } 528